feat(sync): embed basic-auth credentials in restic URL
CI / build (push) Failing after 3s
CI / release (push) Has been skipped

This commit is contained in:
2026-06-02 22:47:43 +02:00
parent 31062e98b9
commit 171ea8f47a
@@ -29,10 +29,24 @@ fun readCredentials(tokenFile: Path): Pair<String, String> {
return parts[0].trim() to parts[1].trim()
}
/** Build the restic --repo URL: rest:<base>/<discord_id>/ */
private fun resticRepo(baseUrl: String, discordId: String): String {
val base = baseUrl.trimEnd('/').let { if (it.startsWith("rest:")) it else "rest:$it" }
return "$base/$discordId/"
/**
* Build the restic --repo URL: rest:<scheme>://<discord_id>:<password>@<host>/<discord_id>/
*
* URL-embedded basic auth is universally supported by restic; the alternative
* (RESTIC_REST_USERNAME / RESTIC_REST_PASSWORD env vars) requires restic 0.16+.
* Same password is used for HTTP basic auth and restic repo encryption —
* cloud-svc provisions one password per user covering both.
*/
private fun resticRepo(baseUrl: String, discordId: String, password: String): String {
val raw = baseUrl.trimStart().removePrefix("rest:").trimEnd('/')
val schemeEnd = raw.indexOf("://")
require(schemeEnd > 0) { "--url must include a scheme (http:// or https://): $baseUrl" }
val scheme = raw.substring(0, schemeEnd + 3)
val hostAndPath = raw.substring(schemeEnd + 3)
// URL-encode credentials to handle special chars in the password
val u = java.net.URLEncoder.encode(discordId, Charsets.UTF_8)
val p = java.net.URLEncoder.encode(password, Charsets.UTF_8)
return "rest:$scheme$u:$p@$hostAndPath/$discordId/"
}
/** Common env applied to every restic invocation. */
@@ -52,7 +66,7 @@ private fun resticEnv(password: String): Map<String, String> = mapOf(
fun pull(args: Args): Int {
val (discordId, password) = readCredentials(args.tokenFile)
val binary = Restic.resolveBinary(args)
val repo = resticRepo(args.url, discordId)
val repo = resticRepo(args.url, discordId, password)
val env = resticEnv(password)
// Check whether any snapshots exist
@@ -103,7 +117,7 @@ fun pull(args: Args): Int {
fun push(args: Args): Int {
val (discordId, password) = readCredentials(args.tokenFile)
val binary = Restic.resolveBinary(args)
val repo = resticRepo(args.url, discordId)
val repo = resticRepo(args.url, discordId, password)
val env = resticEnv(password)
val scope = Scope_.load(args.packFolder)