summaryrefslogtreecommitdiff
path: root/packages/anastasis-core
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-11-04 20:16:11 +0100
committerFlorian Dold <florian@dold.me>2021-11-04 20:16:17 +0100
commitb94dc8f9e26219b1f54e1456f8d7be00d333aa80 (patch)
treeea2d7796610ab6ffa30837f4c8f8f465d154de7d /packages/anastasis-core
parent11e8060ab156e5033c7dd5cd607648d584540883 (diff)
downloadwallet-core-b94dc8f9e26219b1f54e1456f8d7be00d333aa80.tar.gz
wallet-core-b94dc8f9e26219b1f54e1456f8d7be00d333aa80.tar.bz2
wallet-core-b94dc8f9e26219b1f54e1456f8d7be00d333aa80.zip
anastasis-core: factor out recovery data computation into separate step
Diffstat (limited to 'packages/anastasis-core')
-rw-r--r--packages/anastasis-core/src/index.ts100
-rw-r--r--packages/anastasis-core/src/reducer-types.ts14
2 files changed, 75 insertions, 39 deletions
diff --git a/packages/anastasis-core/src/index.ts b/packages/anastasis-core/src/index.ts
index 0bab510de..f77707ae1 100644
--- a/packages/anastasis-core/src/index.ts
+++ b/packages/anastasis-core/src/index.ts
@@ -343,14 +343,19 @@ async function uncompressRecoveryDoc(zippedRd: Uint8Array): Promise<any> {
return JSON.parse(bytesToString(res));
}
-async function uploadSecret(
+/**
+ * Prepare the recovery document and truth metadata based
+ * on the selected policies.
+ */
+async function prepareRecoveryData(
state: ReducerStateBackup,
-): Promise<ReducerStateBackup | ReducerStateError> {
+): Promise<ReducerStateBackup> {
const policies = state.policies!;
const secretName = state.secret_name!;
const coreSecret: OpaqueData = encodeCrock(
stringToBytes(JSON.stringify(state.core_secret!)),
);
+
// Truth key is `${methodIndex}/${providerUrl}`
const truthMetadataMap: Record<string, TruthMetaData> = {};
@@ -391,6 +396,53 @@ async function uploadSecret(
const csr = await coreSecretEncrypt(policyKeys, coreSecret);
+ const escrowMethods: EscrowMethod[] = [];
+
+ for (const truthKey of Object.keys(truthMetadataMap)) {
+ const tm = truthMetadataMap[truthKey];
+ const pol = state.policies![tm.policy_index];
+ const meth = pol.methods[tm.pol_method_index];
+ const authMethod =
+ state.authentication_methods![meth.authentication_method];
+ const provider = state.authentication_providers![
+ meth.provider
+ ] as AuthenticationProviderStatusOk;
+ escrowMethods.push({
+ escrow_type: authMethod.type as any,
+ instructions: authMethod.instructions,
+ provider_salt: provider.salt,
+ truth_salt: tm.truth_salt,
+ truth_key: tm.truth_key,
+ url: meth.provider,
+ uuid: tm.uuid,
+ });
+ }
+
+ const rd: RecoveryDocument = {
+ secret_name: secretName,
+ encrypted_core_secret: csr.encCoreSecret,
+ escrow_methods: escrowMethods,
+ policies: policies.map((x, i) => {
+ return {
+ master_key: csr.encMasterKeys[i],
+ uuids: policyUuids[i],
+ salt: policySalts[i],
+ };
+ }),
+ };
+
+ return {
+ ...state,
+ recovery_data: {
+ recovery_document: rd,
+ truth_metadata: truthMetadataMap,
+ },
+ };
+}
+
+async function uploadSecret(
+ state: ReducerStateBackup,
+): Promise<ReducerStateBackup | ReducerStateError> {
const uidMap: Record<string, UserIdentifier> = {};
for (const prov of state.policy_providers!) {
const provider = state.authentication_providers![
@@ -402,7 +454,17 @@ async function uploadSecret(
);
}
- const escrowMethods: EscrowMethod[] = [];
+ if (!state.recovery_data) {
+ state = await prepareRecoveryData(state);
+ }
+
+ const recoveryData = state.recovery_data;
+ if (!recoveryData) {
+ throw Error("invariant failed");
+ }
+
+ const truthMetadataMap = recoveryData.truth_metadata;
+ const rd = recoveryData.recovery_document;
for (const truthKey of Object.keys(truthMetadataMap)) {
const tm = truthMetadataMap[truthKey];
@@ -410,9 +472,6 @@ async function uploadSecret(
const meth = pol.methods[tm.pol_method_index];
const authMethod =
state.authentication_methods![meth.authentication_method];
- const provider = state.authentication_providers![
- meth.provider
- ] as AuthenticationProviderStatusOk;
const truthValue = await getTruthValue(authMethod, tm.uuid, tm.truth_salt);
const encryptedTruth = await encryptTruth(
tm.nonce,
@@ -448,35 +507,8 @@ async function uploadSecret(
hint: `could not upload truth (HTTP status ${resp.status})`,
};
}
-
- escrowMethods.push({
- escrow_type: authMethod.type as any,
- instructions: authMethod.instructions,
- provider_salt: provider.salt,
- truth_salt: tm.truth_salt,
- truth_key: tm.truth_key,
- url: meth.provider,
- uuid: tm.uuid,
- });
}
- // FIXME: We need to store the truth metadata in
- // the state, since it's possible that we'll run into
- // a provider that requests a payment.
-
- const rd: RecoveryDocument = {
- secret_name: secretName,
- encrypted_core_secret: csr.encCoreSecret,
- escrow_methods: escrowMethods,
- policies: policies.map((x, i) => {
- return {
- master_key: csr.encMasterKeys[i],
- uuids: policyUuids[i],
- salt: policySalts[i],
- };
- }),
- };
-
const successDetails: SuccessDetails = {};
const policyPayUris: string[] = [];
@@ -1092,6 +1124,8 @@ async function enterSecret(
mime: args.secret.mime ?? "text/plain",
value: args.secret.value,
},
+ // A new secret invalidates the existing recovery data.
+ recovery_data: undefined,
});
}
diff --git a/packages/anastasis-core/src/reducer-types.ts b/packages/anastasis-core/src/reducer-types.ts
index 318e00f89..56b27898e 100644
--- a/packages/anastasis-core/src/reducer-types.ts
+++ b/packages/anastasis-core/src/reducer-types.ts
@@ -67,12 +67,14 @@ export interface ReducerStateBackup {
secret_name?: string;
policies?: Policy[];
- /**
- * Map from truth key (`${methodIndex}/${providerUrl}`) to
- * the truth metadata.
- */
- truth_metadata?: Record<string, TruthMetaData>;
- recovery_document?: RecoveryDocument;
+ recovery_data?: {
+ /**
+ * Map from truth key (`${methodIndex}/${providerUrl}`) to
+ * the truth metadata.
+ */
+ truth_metadata: Record<string, TruthMetaData>;
+ recovery_document: RecoveryDocument;
+ };
/**
* Policy providers are providers that we checked to be functional