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()
|
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 {
|
* Build the restic --repo URL: rest:<scheme>://<discord_id>:<password>@<host>/<discord_id>/
|
||||||
val base = baseUrl.trimEnd('/').let { if (it.startsWith("rest:")) it else "rest:$it" }
|
*
|
||||||
return "$base/$discordId/"
|
* 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. */
|
/** 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 {
|
fun pull(args: Args): Int {
|
||||||
val (discordId, password) = readCredentials(args.tokenFile)
|
val (discordId, password) = readCredentials(args.tokenFile)
|
||||||
val binary = Restic.resolveBinary(args)
|
val binary = Restic.resolveBinary(args)
|
||||||
val repo = resticRepo(args.url, discordId)
|
val repo = resticRepo(args.url, discordId, password)
|
||||||
val env = resticEnv(password)
|
val env = resticEnv(password)
|
||||||
|
|
||||||
// Check whether any snapshots exist
|
// Check whether any snapshots exist
|
||||||
@@ -103,7 +117,7 @@ fun pull(args: Args): Int {
|
|||||||
fun push(args: Args): Int {
|
fun push(args: Args): Int {
|
||||||
val (discordId, password) = readCredentials(args.tokenFile)
|
val (discordId, password) = readCredentials(args.tokenFile)
|
||||||
val binary = Restic.resolveBinary(args)
|
val binary = Restic.resolveBinary(args)
|
||||||
val repo = resticRepo(args.url, discordId)
|
val repo = resticRepo(args.url, discordId, password)
|
||||||
val env = resticEnv(password)
|
val env = resticEnv(password)
|
||||||
|
|
||||||
val scope = Scope_.load(args.packFolder)
|
val scope = Scope_.load(args.packFolder)
|
||||||
|
|||||||
Reference in New Issue
Block a user