feat(sync): embed basic-auth credentials in restic URL
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user