mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-10-26 11:03:21 +00:00
Read Setup URI generator values from LIVESYNC_ variables
hostname, username, and the other unprefixed names collide with shell and system variables (fish makes hostname read-only, Windows already defines USERNAME). The generator now reads LIVESYNC_HOST, LIVESYNC_USER, LIVESYNC_PASS, LIVESYNC_DB, and LIVESYNC_PASSPHRASE first and falls back to the old names, so existing instructions keep working. Co-authored-by: rwbru <59871009+rwbru@users.noreply.github.com>
This commit is contained in:
1 parent
ce0524d49f
commit
b35ac635d0
7 files changed
+114
-24
No files matched your search
@@ -24,7 +24,7 @@ export secret_key=<SECRET KEY>
|
|||||||
export bucket=vault-data
|
export bucket=vault-data
|
||||||
export region=auto
|
export region=auto
|
||||||
export bucket_prefix=my-vault
|
export bucket_prefix=my-vault
|
||||||
export passphrase=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
export LIVESYNC_PASSPHRASE=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
||||||
export uri_passphrase=<A SEPARATE SETUP URI PASSPHRASE>
|
export uri_passphrase=<A SEPARATE SETUP URI PASSPHRASE>
|
||||||
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -128,6 +128,9 @@ export database=obsidiannotes
|
|||||||
curl -s https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh | bash
|
curl -s https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh | bash
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> [!TIP]
|
||||||
|
> In fish, `hostname` is read-only and cannot be exported. Pass the values through `env` instead: `curl -s https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/couchdb/couchdb-init.sh | env hostname=http://localhost:5984 username=<...> password=<...> database=obsidiannotes bash`.
|
||||||
|
|
||||||
If it results like the following:
|
If it results like the following:
|
||||||
```
|
```
|
||||||
CouchDB provisioning completed.
|
CouchDB provisioning completed.
|
||||||
@@ -173,20 +176,20 @@ Now `https://tiles-photograph-routine-groundwater.trycloudflare.com` is our serv
|
|||||||
|
|
||||||
### 1. Generate the setup URI on a desktop device or server
|
### 1. Generate the setup URI on a desktop device or server
|
||||||
|
|
||||||
The `username` and `password` here are the credentials which Self-hosted LiveSync will store for routine access to this database. They may be the administrator credentials from step 2. If you have separately configured a CouchDB account with the required access to this database, use that account instead. Neither the provisioning wrapper nor the Setup URI generator creates that separate account.
|
The `LIVESYNC_USER` and `LIVESYNC_PASS` here are the credentials which Self-hosted LiveSync will store for routine access to this database. They may be the administrator credentials from step 2. If you have separately configured a CouchDB account with the required access to this database, use that account instead. Neither the provisioning wrapper nor the Setup URI generator creates that separate account.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export hostname=https://tiles-photograph-routine-groundwater.trycloudflare.com
|
export LIVESYNC_HOST=https://tiles-photograph-routine-groundwater.trycloudflare.com
|
||||||
export database=obsidiannotes
|
export LIVESYNC_DB=obsidiannotes
|
||||||
export username=<INSERT COUCHDB USERNAME FOR LIVESYNC>
|
export LIVESYNC_USER=<INSERT COUCHDB USERNAME FOR LIVESYNC>
|
||||||
export password=<INSERT THE COUCHDB PASSWORD>
|
export LIVESYNC_PASS=<INSERT THE COUCHDB PASSWORD>
|
||||||
export passphrase=<INSERT A STRONG VAULT ENCRYPTION PASSPHRASE>
|
export LIVESYNC_PASSPHRASE=<INSERT A STRONG VAULT ENCRYPTION PASSPHRASE>
|
||||||
export uri_passphrase=<INSERT A SEPARATE SETUP URI PASSPHRASE> # Optional
|
export uri_passphrase=<INSERT A SEPARATE SETUP URI PASSPHRASE> # Optional
|
||||||
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
> [!TIP]
|
> [!TIP]
|
||||||
> `passphrase` protects the synchronised Vault data with end-to-end encryption. `uri_passphrase` protects only the Setup URI. Use different values, store both securely, and do not send the Setup URI and its passphrase through the same channel.
|
> `LIVESYNC_PASSPHRASE` protects the synchronised Vault data with end-to-end encryption. `uri_passphrase` protects only the Setup URI. Use different values, store both securely, and do not send the Setup URI and its passphrase through the same channel.
|
||||||
>
|
>
|
||||||
> If `uri_passphrase` is omitted, the generator creates a cryptographically random value and prints it once.
|
> If `uri_passphrase` is omitted, the generator creates a cryptographically random value and prints it once.
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -130,7 +130,7 @@ export remote_type=p2p
|
|||||||
export p2p_relays=wss://relay.example.com
|
export p2p_relays=wss://relay.example.com
|
||||||
export p2p_room_id=<A PRIVATE ROOM ID> # Optional; generated when omitted
|
export p2p_room_id=<A PRIVATE ROOM ID> # Optional; generated when omitted
|
||||||
export p2p_passphrase=<A PRIVATE P2P PASSPHRASE> # Optional; generated when omitted
|
export p2p_passphrase=<A PRIVATE P2P PASSPHRASE> # Optional; generated when omitted
|
||||||
export passphrase=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
export LIVESYNC_PASSPHRASE=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
||||||
export uri_passphrase=<A SEPARATE SETUP URI PASSPHRASE>
|
export uri_passphrase=<A SEPARATE SETUP URI PASSPHRASE>
|
||||||
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
deno run --minimum-dependency-age=0 --allow-env https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/setup/generate_setup_uri.ts
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ Earlier releases remain available in the 1.0 release history, the 1.0 preview hi
|
|||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
### Setup tools
|
||||||
|
|
||||||
|
#### Fixed
|
||||||
|
|
||||||
|
- We can generate a Setup URI from fish, PowerShell, or cmd without the connection details colliding with `hostname` or `USERNAME`. (#817)
|
||||||
|
- The generator reads `LIVESYNC_HOST`, `LIVESYNC_USER`, `LIVESYNC_PASS`, `LIVESYNC_DB`, and `LIVESYNC_PASSPHRASE`. The previous names are still read when these are not set.
|
||||||
|
|
||||||
## 1.0.39
|
## 1.0.39
|
||||||
|
|
||||||
20th October, 2026
|
20th October, 2026
|
||||||
|
|||||||
+10
-8
@@ -31,21 +31,23 @@ Authentication and other non-retryable HTTP failures stop immediately. Network a
|
|||||||
|
|
||||||
The existing `flyio/generate_setupuri.ts` path remains a CouchDB-only compatibility wrapper for the Fly.io deployment script.
|
The existing `flyio/generate_setupuri.ts` path remains a CouchDB-only compatibility wrapper for the Fly.io deployment script.
|
||||||
|
|
||||||
|
The connection and Vault encryption values use a `LIVESYNC_` prefix so that they do not collide with shell or system variables such as `hostname` and `USERNAME`. The unprefixed names `hostname`, `username`, `password`, `database`, and `passphrase` are still read when the prefixed ones are not set.
|
||||||
|
|
||||||
The generator creates a fresh random ID key by default and includes it in the encrypted Setup URI. It prints a tagged `sls-id-v1:` recovery code. Set `id_recovery_code` to that code when generating another URI for the same Vault; a new run without it creates a different key. This restores only the ID key: reuse the original connection details too. For P2P, provide the original `p2p_room_id` and `p2p_passphrase` because omitted values are generated afresh. Set `id_mode=legacy` to generate a URI with the previous ID behaviour. `id_mode=legacy` and `id_recovery_code` cannot be combined. Keep the recovery code private and retain it if every device might be lost.
|
The generator creates a fresh random ID key by default and includes it in the encrypted Setup URI. It prints a tagged `sls-id-v1:` recovery code. Set `id_recovery_code` to that code when generating another URI for the same Vault; a new run without it creates a different key. This restores only the ID key: reuse the original connection details too. For P2P, provide the original `p2p_room_id` and `p2p_passphrase` because omitted values are generated afresh. Set `id_mode=legacy` to generate a URI with the previous ID behaviour. `id_mode=legacy` and `id_recovery_code` cannot be combined. Keep the recovery code private and retain it if every device might be lost.
|
||||||
|
|
||||||
### CouchDB
|
### CouchDB
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
export hostname=https://couch.example.com
|
export LIVESYNC_HOST=https://couch.example.com
|
||||||
export username=couchdb-admin-username
|
export LIVESYNC_USER=couchdb-admin-username
|
||||||
export password=couchdb-admin-password
|
export LIVESYNC_PASS=couchdb-admin-password
|
||||||
export database=obsidiannotes
|
export LIVESYNC_DB=obsidiannotes
|
||||||
export passphrase=a-strong-vault-encryption-passphrase
|
export LIVESYNC_PASSPHRASE=a-strong-vault-encryption-passphrase
|
||||||
export uri_passphrase=a-separate-setup-uri-passphrase # Optional
|
export uri_passphrase=a-separate-setup-uri-passphrase # Optional
|
||||||
deno run --minimum-dependency-age=0 --config=./flyio/deno.jsonc --frozen --lock=./flyio/deno.lock --allow-env ./setup/generate_setup_uri.ts
|
deno run --minimum-dependency-age=0 --config=./flyio/deno.jsonc --frozen --lock=./flyio/deno.lock --allow-env ./setup/generate_setup_uri.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
If `uri_passphrase` is omitted, the tool generates and prints a cryptographically random one. Store the Setup URI and its passphrase separately. The `passphrase` value protects synchronised Vault data and must also be stored safely.
|
If `uri_passphrase` is omitted, the tool generates and prints a cryptographically random one. Store the Setup URI and its passphrase separately. The `LIVESYNC_PASSPHRASE` value protects synchronised Vault data and must also be stored safely.
|
||||||
|
|
||||||
The generator defaults to `uri_mode=ephemeral`. The URI opens only during the current fixed seven-day UTC window, and the tool prints its exact end time. It may have less than seven days remaining when generated. For an indefinitely reusable URI, set `uri_mode=persistent` before running the command. Persistent uses the existing encrypted format, which older clients that already support that format can read. The time condition controls opening the URI; it does not revoke settings or credentials after import.
|
The generator defaults to `uri_mode=ephemeral`. The URI opens only during the current fixed seven-day UTC window, and the tool prints its exact end time. It may have less than seven days remaining when generated. For an indefinitely reusable URI, set `uri_mode=persistent` before running the command. Persistent uses the existing encrypted format, which older clients that already support that format can read. The time condition controls opening the URI; it does not revoke settings or credentials after import.
|
||||||
|
|
||||||
@@ -59,7 +61,7 @@ export secret_key=<SECRET KEY>
|
|||||||
export bucket=vault-data
|
export bucket=vault-data
|
||||||
export region=auto
|
export region=auto
|
||||||
export bucket_prefix=team-a # Optional
|
export bucket_prefix=team-a # Optional
|
||||||
export passphrase=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
export LIVESYNC_PASSPHRASE=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
||||||
deno run --minimum-dependency-age=0 --config=./flyio/deno.jsonc --frozen --lock=./flyio/deno.lock --allow-env ./setup/generate_setup_uri.ts
|
deno run --minimum-dependency-age=0 --config=./flyio/deno.jsonc --frozen --lock=./flyio/deno.lock --allow-env ./setup/generate_setup_uri.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -69,7 +71,7 @@ Optional Object Storage variables are `use_custom_request_handler`, `force_path_
|
|||||||
|
|
||||||
```sh
|
```sh
|
||||||
export remote_type=p2p
|
export remote_type=p2p
|
||||||
export passphrase=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
export LIVESYNC_PASSPHRASE=<A STRONG VAULT ENCRYPTION PASSPHRASE>
|
||||||
deno run --minimum-dependency-age=0 --config=./flyio/deno.jsonc --frozen --lock=./flyio/deno.lock --allow-env ./setup/generate_setup_uri.ts
|
deno run --minimum-dependency-age=0 --config=./flyio/deno.jsonc --frozen --lock=./flyio/deno.lock --allow-env ./setup/generate_setup_uri.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,76 @@ function assert(condition: unknown, message: string): asserts condition {
|
|||||||
if (!condition) throw new Error(message);
|
if (!condition) throw new Error(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Deno.test("reads LIVESYNC_ variables before the unprefixed names", async () => {
|
||||||
|
const generated = await generateSetupURI({
|
||||||
|
LIVESYNC_HOST: "https://couch.example.test",
|
||||||
|
LIVESYNC_USER: "alice",
|
||||||
|
LIVESYNC_PASS: "couch-secret",
|
||||||
|
LIVESYNC_DB: "notes",
|
||||||
|
LIVESYNC_PASSPHRASE: "vault-secret",
|
||||||
|
hostname: "https://shell.example.test",
|
||||||
|
username: "shell-user",
|
||||||
|
password: "shell-secret",
|
||||||
|
database: "shell-db",
|
||||||
|
passphrase: "shell-passphrase",
|
||||||
|
uri_passphrase: "setup-secret",
|
||||||
|
});
|
||||||
|
const decoded = await decodeSettingsFromSetupURI(
|
||||||
|
generated.setupURI,
|
||||||
|
generated.setupPassphrase,
|
||||||
|
);
|
||||||
|
assert(decoded, "Commonlib could not decode the CouchDB Setup URI");
|
||||||
|
const effective = { ...DEFAULT_SETTINGS, ...decoded };
|
||||||
|
assert(
|
||||||
|
effective.couchDB_URI === "https://couch.example.test" &&
|
||||||
|
effective.couchDB_USER === "alice" &&
|
||||||
|
effective.couchDB_PASSWORD === "couch-secret" &&
|
||||||
|
effective.couchDB_DBNAME === "notes",
|
||||||
|
"the CouchDB connection did not come from the LIVESYNC_ variables",
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
effective.passphrase === "vault-secret",
|
||||||
|
"the Vault passphrase did not come from LIVESYNC_PASSPHRASE",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("falls back to the unprefixed names when LIVESYNC_ variables are blank", async () => {
|
||||||
|
const generated = await generateSetupURI({
|
||||||
|
LIVESYNC_HOST: " ",
|
||||||
|
hostname: "https://couch.example.test",
|
||||||
|
username: "alice",
|
||||||
|
password: "couch-secret",
|
||||||
|
database: "notes",
|
||||||
|
passphrase: "vault-secret",
|
||||||
|
uri_passphrase: "setup-secret",
|
||||||
|
});
|
||||||
|
const decoded = await decodeSettingsFromSetupURI(
|
||||||
|
generated.setupURI,
|
||||||
|
generated.setupPassphrase,
|
||||||
|
);
|
||||||
|
assert(decoded, "Commonlib could not decode the CouchDB Setup URI");
|
||||||
|
const effective = { ...DEFAULT_SETTINGS, ...decoded };
|
||||||
|
assert(
|
||||||
|
effective.couchDB_URI === "https://couch.example.test" &&
|
||||||
|
effective.couchDB_USER === "alice" &&
|
||||||
|
effective.couchDB_PASSWORD === "couch-secret" &&
|
||||||
|
effective.couchDB_DBNAME === "notes" &&
|
||||||
|
effective.passphrase === "vault-secret",
|
||||||
|
"the generator did not fall back to the unprefixed names",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Deno.test("names both variables when a CouchDB value is missing", async () => {
|
||||||
|
let rejected = false;
|
||||||
|
try {
|
||||||
|
await generateSetupURI({ uri_passphrase: "setup-secret" });
|
||||||
|
} catch (error) {
|
||||||
|
rejected = error instanceof Error &&
|
||||||
|
error.message === "LIVESYNC_HOST (or hostname) is required";
|
||||||
|
}
|
||||||
|
assert(rejected, "the generator did not name both host variables");
|
||||||
|
});
|
||||||
|
|
||||||
Deno.test("generates an Object Storage Setup URI with a selected S3 profile", async () => {
|
Deno.test("generates an Object Storage Setup URI with a selected S3 profile", async () => {
|
||||||
const generated = await generateSetupURI({
|
const generated = await generateSetupURI({
|
||||||
remote_type: "s3",
|
remote_type: "s3",
|
||||||
|
|||||||
@@ -64,9 +64,17 @@ function configureIdDerivation(
|
|||||||
function requireValue(
|
function requireValue(
|
||||||
environment: SetupGeneratorEnvironment,
|
environment: SetupGeneratorEnvironment,
|
||||||
name: string,
|
name: string,
|
||||||
|
legacyName?: string,
|
||||||
): string {
|
): string {
|
||||||
const value = environment[name]?.trim();
|
const value = environment[name]?.trim() ||
|
||||||
if (!value) throw new Error(`${name} is required`);
|
(legacyName && environment[legacyName]?.trim());
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(
|
||||||
|
legacyName
|
||||||
|
? `${name} (or ${legacyName}) is required`
|
||||||
|
: `${name} is required`,
|
||||||
|
);
|
||||||
|
}
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +105,7 @@ function applyEncryptedVaultSettings(
|
|||||||
Object.assign(settings, {
|
Object.assign(settings, {
|
||||||
isConfigured: true,
|
isConfigured: true,
|
||||||
encrypt: true,
|
encrypt: true,
|
||||||
passphrase: requireValue(environment, "passphrase"),
|
passphrase: requireValue(environment, "LIVESYNC_PASSPHRASE", "passphrase"),
|
||||||
usePathObfuscation: true,
|
usePathObfuscation: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -107,10 +115,10 @@ function createCouchDBSettings(
|
|||||||
): ObsidianLiveSyncSettings {
|
): ObsidianLiveSyncSettings {
|
||||||
const settings = createNewVaultSettings();
|
const settings = createNewVaultSettings();
|
||||||
Object.assign(settings, PREFERRED_SETTING_SELF_HOSTED, {
|
Object.assign(settings, PREFERRED_SETTING_SELF_HOSTED, {
|
||||||
couchDB_URI: requireValue(environment, "hostname"),
|
couchDB_URI: requireValue(environment, "LIVESYNC_HOST", "hostname"),
|
||||||
couchDB_USER: requireValue(environment, "username"),
|
couchDB_USER: requireValue(environment, "LIVESYNC_USER", "username"),
|
||||||
couchDB_PASSWORD: requireValue(environment, "password"),
|
couchDB_PASSWORD: requireValue(environment, "LIVESYNC_PASS", "password"),
|
||||||
couchDB_DBNAME: requireValue(environment, "database"),
|
couchDB_DBNAME: requireValue(environment, "LIVESYNC_DB", "database"),
|
||||||
batchSave: true,
|
batchSave: true,
|
||||||
periodicReplication: true,
|
periodicReplication: true,
|
||||||
syncOnStart: true,
|
syncOnStart: true,
|
||||||
|
|||||||
Reference in new issue
Block a user