openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
171 lines (170 loc) • 6.51 kB
JavaScript
import { p as isValidEnvSecretRefId } from "./types.secrets-kC0nOetj.js";
import { i as registerSecretValueForRedaction } from "./secret-redaction-registry-BOLC6DkF.js";
import { u as resolveDefaultSecretProviderAlias } from "./ref-contract-D92DqQ-r.js";
import { c as readSecretStoreValue, r as deleteSecretStoreEntry, u as writeSecretStoreEntry } from "./secret-store-CC1e6gjb.js";
import { l as persistAuthProfileBatch } from "./profiles-DOTqXcYA.js";
import "./auth-profiles-BdUEhE7u.js";
import { createHash } from "node:crypto";
//#region src/plugins/provider-auth-persistence.ts
const STORE_SCOPE = { kind: "team" };
const STORE_NAME_DIGEST_LENGTH = 24;
function resolveStoreName(profile) {
const storage = profile.secretStorage;
if (!storage) throw new Error("Provider auth profile does not request protected secret storage.");
const name = `${storage.namePrefix.trim()}_${createHash("sha256").update(profile.credential.provider).update("\0").update(profile.profileId).digest("hex").slice(0, STORE_NAME_DIGEST_LENGTH).toUpperCase()}`;
if (!isValidEnvSecretRefId(name)) throw new Error("Provider auth secret-store name prefix must produce a valid environment-style name.");
return name;
}
function buildStoredCredential(profile, ref) {
const credential = profile.credential;
if (credential.type === "token" && typeof credential.token === "string") {
const { token: _token, ...withoutToken } = credential;
return {
...withoutToken,
tokenRef: ref
};
}
if (credential.type === "api_key" && typeof credential.key === "string") {
const { key: _key, ...withoutKey } = credential;
return {
...withoutKey,
keyRef: ref
};
}
throw new Error(`Provider auth profile "${profile.profileId}" requested protected storage without an inline static credential.`);
}
function rollbackStoreWrites(writes, database) {
const errors = [];
for (const write of writes.toReversed()) try {
if (write.previousValue === void 0) deleteSecretStoreEntry({
scope: STORE_SCOPE,
name: write.name,
database
});
else writeSecretStoreEntry({
scope: STORE_SCOPE,
name: write.name,
value: write.previousValue,
kind: "secret",
updatedBy: "provider-auth-rollback",
database
});
} catch (error) {
errors.push(error);
}
if (errors.length > 0) throw new AggregateError(errors, "Could not confirm rollback of protected provider credentials; run openclaw doctor --fix before retrying.");
}
/** Materializes provider-minted static credentials only when their final persistence begins. */
function prepareProviderAuthProfilesForPersistence(params) {
const database = params.env ? { env: params.env } : void 0;
const writes = [];
let rolledBack = false;
const rollback = () => {
if (rolledBack) return;
rollbackStoreWrites(writes, database);
rolledBack = true;
};
try {
return {
profiles: params.profiles.map((profile) => {
if (!profile.secretStorage) return profile;
const name = resolveStoreName(profile);
const existing = readSecretStoreValue({
scope: STORE_SCOPE,
name,
database
});
if (!existing.ok && existing.error.code !== "SECRET_STORE_NOT_FOUND") throw new Error("The protected secret store is unavailable. Check the OpenClaw state-directory permissions and retry; the auth profile was not changed.", { cause: existing.error });
const credential = profile.credential;
const value = credential.type === "token" ? credential.token : credential.type === "api_key" ? credential.key : void 0;
if (typeof value !== "string") throw new Error(`Provider auth profile "${profile.profileId}" requested protected storage without an inline static credential.`);
registerSecretValueForRedaction(value);
try {
writeSecretStoreEntry({
scope: STORE_SCOPE,
name,
value,
kind: "secret",
updatedBy: "provider-auth",
database
});
} catch (error) {
throw new Error("Could not write the protected secret store. Check the OpenClaw state-directory permissions and retry; the auth profile was not changed.", { cause: error });
}
writes.push({
name,
...existing.ok ? { previousValue: existing.value } : {}
});
const ref = {
source: "store",
provider: resolveDefaultSecretProviderAlias(params.config, "store", { preferFirstProviderForSource: true }),
id: name
};
const { secretStorage: _secretStorage, ...persistentProfile } = profile;
return {
...persistentProfile,
credential: buildStoredCredential(profile, ref)
};
}),
rollback
};
} catch (error) {
try {
rollback();
} catch (rollbackError) {
throw new AggregateError([error, rollbackError], "Provider credential persistence failed and protected-store rollback could not be confirmed.", { cause: rollbackError });
}
throw error;
}
}
/** Persists a provider-auth batch and couples its rollback to protected-store materialization. */
async function persistProviderAuthProfileBatch(params) {
const env = params.stateDir ? {
...params.env ?? process.env,
OPENCLAW_STATE_DIR: params.stateDir
} : params.env;
const prepared = prepareProviderAuthProfilesForPersistence({
profiles: params.profiles,
config: params.config,
...env ? { env } : {}
});
let persisted;
try {
persisted = await persistAuthProfileBatch({
profiles: prepared.profiles,
...params.order ? { order: params.order } : {},
...params.agentDir ? { agentDir: params.agentDir } : {},
...params.stateDir ? { stateDir: params.stateDir } : {}
});
} catch (error) {
try {
prepared.rollback();
} catch (rollbackError) {
throw new AggregateError([error, rollbackError], "Provider auth persistence failed and protected-store rollback could not be confirmed.", { cause: rollbackError });
}
throw error;
}
let rolledBack = false;
return {
profiles: prepared.profiles,
rollback: () => {
if (rolledBack) return;
let profileError;
try {
persisted.rollback();
} catch (error) {
profileError = error instanceof Error ? error : new Error(String(error), { cause: error });
}
try {
prepared.rollback();
} catch (error) {
if (profileError) throw new AggregateError([profileError, error], "Could not confirm rollback of provider auth profiles and protected credentials.", { cause: error });
throw error;
}
if (profileError) throw profileError;
rolledBack = true;
}
};
}
//#endregion
export { prepareProviderAuthProfilesForPersistence as n, persistProviderAuthProfileBatch as t };