anastasis-core: make truth/policy payments compatible with C reducer
This commit is contained in:
parent
34d2e4703d
commit
e42c282e67
@ -11,8 +11,9 @@ import {
|
|||||||
stringToBytes,
|
stringToBytes,
|
||||||
secretbox_open,
|
secretbox_open,
|
||||||
hash,
|
hash,
|
||||||
|
Logger,
|
||||||
|
j2s,
|
||||||
} from "@gnu-taler/taler-util";
|
} from "@gnu-taler/taler-util";
|
||||||
import { gzipSync } from "fflate";
|
|
||||||
import { argon2id } from "hash-wasm";
|
import { argon2id } from "hash-wasm";
|
||||||
|
|
||||||
export type Flavor<T, FlavorT extends string> = T & {
|
export type Flavor<T, FlavorT extends string> = T & {
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
HttpStatusCode,
|
HttpStatusCode,
|
||||||
j2s,
|
j2s,
|
||||||
Logger,
|
Logger,
|
||||||
|
parsePayUri,
|
||||||
stringToBytes,
|
stringToBytes,
|
||||||
TalerErrorCode,
|
TalerErrorCode,
|
||||||
TalerSignaturePurpose,
|
TalerSignaturePurpose,
|
||||||
@ -328,7 +329,6 @@ async function getTruthValue(
|
|||||||
* Compress the recovery document and add a size header.
|
* Compress the recovery document and add a size header.
|
||||||
*/
|
*/
|
||||||
async function compressRecoveryDoc(rd: any): Promise<Uint8Array> {
|
async function compressRecoveryDoc(rd: any): Promise<Uint8Array> {
|
||||||
logger.info(`recovery document: ${j2s(rd)}`);
|
|
||||||
const docBytes = stringToBytes(JSON.stringify(rd));
|
const docBytes = stringToBytes(JSON.stringify(rd));
|
||||||
const sizeHeaderBuf = new ArrayBuffer(4);
|
const sizeHeaderBuf = new ArrayBuffer(4);
|
||||||
const dvbuf = new DataView(sizeHeaderBuf);
|
const dvbuf = new DataView(sizeHeaderBuf);
|
||||||
@ -457,6 +457,8 @@ async function uploadSecret(
|
|||||||
const rd = recoveryData.recovery_document;
|
const rd = recoveryData.recovery_document;
|
||||||
|
|
||||||
const truthPayUris: string[] = [];
|
const truthPayUris: string[] = [];
|
||||||
|
const truthPaySecrets: Record<string, string> = {};
|
||||||
|
|
||||||
const userIdCache: Record<string, UserIdentifier> = {};
|
const userIdCache: Record<string, UserIdentifier> = {};
|
||||||
const getUserIdCaching = async (providerUrl: string) => {
|
const getUserIdCaching = async (providerUrl: string) => {
|
||||||
let userId = userIdCache[providerUrl];
|
let userId = userIdCache[providerUrl];
|
||||||
@ -483,9 +485,8 @@ async function uploadSecret(
|
|||||||
tm.truth_key,
|
tm.truth_key,
|
||||||
truthValue,
|
truthValue,
|
||||||
);
|
);
|
||||||
logger.info(`uploading to ${meth.provider}`);
|
logger.info(`uploading truth to ${meth.provider}`);
|
||||||
const userId = await getUserIdCaching(meth.provider);
|
const userId = await getUserIdCaching(meth.provider);
|
||||||
// FIXME: check that the question salt is okay here, looks weird.
|
|
||||||
const encryptedKeyShare = await encryptKeyshare(
|
const encryptedKeyShare = await encryptKeyshare(
|
||||||
tm.key_share,
|
tm.key_share,
|
||||||
userId,
|
userId,
|
||||||
@ -500,10 +501,21 @@ async function uploadSecret(
|
|||||||
type: authMethod.type,
|
type: authMethod.type,
|
||||||
truth_mime: authMethod.mime_type,
|
truth_mime: authMethod.mime_type,
|
||||||
};
|
};
|
||||||
const resp = await fetch(new URL(`truth/${tm.uuid}`, meth.provider).href, {
|
const reqUrl = new URL(`truth/${tm.uuid}`, meth.provider);
|
||||||
|
const paySecret = (state.truth_upload_payment_secrets ?? {})[meth.provider];
|
||||||
|
if (paySecret) {
|
||||||
|
// FIXME: Get this from the params
|
||||||
|
reqUrl.searchParams.set("timeout_ms", "500");
|
||||||
|
}
|
||||||
|
const resp = await fetch(reqUrl.href, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
|
...(paySecret
|
||||||
|
? {
|
||||||
|
"Anastasis-Payment-Identifier": paySecret,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
},
|
},
|
||||||
body: JSON.stringify(tur),
|
body: JSON.stringify(tur),
|
||||||
});
|
});
|
||||||
@ -520,6 +532,14 @@ async function uploadSecret(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
truthPayUris.push(talerPayUri);
|
truthPayUris.push(talerPayUri);
|
||||||
|
const parsedUri = parsePayUri(talerPayUri);
|
||||||
|
if (!parsedUri) {
|
||||||
|
return {
|
||||||
|
code: TalerErrorCode.ANASTASIS_REDUCER_BACKEND_FAILURE,
|
||||||
|
hint: `payment requested, but no taler://pay URI given`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
truthPaySecrets[meth.provider] = parsedUri.orderId;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -532,6 +552,7 @@ async function uploadSecret(
|
|||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
backup_state: BackupStates.TruthsPaying,
|
backup_state: BackupStates.TruthsPaying,
|
||||||
|
truth_upload_payment_secrets: truthPaySecrets,
|
||||||
payments: truthPayUris,
|
payments: truthPayUris,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -539,6 +560,8 @@ async function uploadSecret(
|
|||||||
const successDetails: SuccessDetails = {};
|
const successDetails: SuccessDetails = {};
|
||||||
|
|
||||||
const policyPayUris: string[] = [];
|
const policyPayUris: string[] = [];
|
||||||
|
const policyPayUriMap: Record<string, string> = {};
|
||||||
|
//const policyPaySecrets: Record<string, string> = {};
|
||||||
|
|
||||||
for (const prov of state.policy_providers!) {
|
for (const prov of state.policy_providers!) {
|
||||||
const userId = await getUserIdCaching(prov.provider_url);
|
const userId = await getUserIdCaching(prov.provider_url);
|
||||||
@ -553,17 +576,33 @@ async function uploadSecret(
|
|||||||
.put(bodyHash)
|
.put(bodyHash)
|
||||||
.build();
|
.build();
|
||||||
const sig = eddsaSign(sigPS, decodeCrock(acctKeypair.priv));
|
const sig = eddsaSign(sigPS, decodeCrock(acctKeypair.priv));
|
||||||
const resp = await fetch(
|
const talerPayUri = state.policy_payment_requests?.find(
|
||||||
new URL(`policy/${acctKeypair.pub}`, prov.provider_url).href,
|
(x) => x.provider === prov.provider_url,
|
||||||
{
|
)?.payto;
|
||||||
method: "POST",
|
let paySecret: string | undefined;
|
||||||
headers: {
|
if (talerPayUri) {
|
||||||
"Anastasis-Policy-Signature": encodeCrock(sig),
|
paySecret = parsePayUri(talerPayUri)!.orderId;
|
||||||
"If-None-Match": encodeCrock(bodyHash),
|
}
|
||||||
},
|
const reqUrl = new URL(`policy/${acctKeypair.pub}`, prov.provider_url);
|
||||||
body: decodeCrock(encRecoveryDoc),
|
if (paySecret) {
|
||||||
|
// FIXME: Get this from the params
|
||||||
|
reqUrl.searchParams.set("timeout_ms", "500");
|
||||||
|
}
|
||||||
|
logger.info(`uploading policy to ${prov.provider_url}`);
|
||||||
|
const resp = await fetch(reqUrl.href, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Anastasis-Policy-Signature": encodeCrock(sig),
|
||||||
|
"If-None-Match": encodeCrock(bodyHash),
|
||||||
|
...(paySecret
|
||||||
|
? {
|
||||||
|
"Anastasis-Payment-Identifier": paySecret,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
},
|
},
|
||||||
);
|
body: decodeCrock(encRecoveryDoc),
|
||||||
|
});
|
||||||
|
logger.info(`got response for policy upload (http status ${resp.status})`);
|
||||||
if (resp.status === HttpStatusCode.NoContent) {
|
if (resp.status === HttpStatusCode.NoContent) {
|
||||||
let policyVersion = 0;
|
let policyVersion = 0;
|
||||||
let policyExpiration: Timestamp = { t_ms: 0 };
|
let policyExpiration: Timestamp = { t_ms: 0 };
|
||||||
@ -592,6 +631,14 @@ async function uploadSecret(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
policyPayUris.push(talerPayUri);
|
policyPayUris.push(talerPayUri);
|
||||||
|
const parsedUri = parsePayUri(talerPayUri);
|
||||||
|
if (!parsedUri) {
|
||||||
|
return {
|
||||||
|
code: TalerErrorCode.ANASTASIS_REDUCER_BACKEND_FAILURE,
|
||||||
|
hint: `payment requested, but no taler://pay URI given`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
policyPayUriMap[prov.provider_url] = talerPayUri;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
@ -605,9 +652,17 @@ async function uploadSecret(
|
|||||||
...state,
|
...state,
|
||||||
backup_state: BackupStates.PoliciesPaying,
|
backup_state: BackupStates.PoliciesPaying,
|
||||||
payments: policyPayUris,
|
payments: policyPayUris,
|
||||||
|
policy_payment_requests: Object.keys(policyPayUriMap).map((x) => {
|
||||||
|
return {
|
||||||
|
payto: policyPayUriMap[x],
|
||||||
|
provider: x,
|
||||||
|
};
|
||||||
|
}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info("backup finished");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
core_secret: undefined,
|
core_secret: undefined,
|
||||||
@ -766,6 +821,7 @@ async function requestTruth(
|
|||||||
const url = new URL(`/truth/${truth.uuid}`, truth.url);
|
const url = new URL(`/truth/${truth.uuid}`, truth.url);
|
||||||
|
|
||||||
if (solveRequest) {
|
if (solveRequest) {
|
||||||
|
logger.info(`handling solve request ${j2s(solveRequest)}`);
|
||||||
let respHash: string;
|
let respHash: string;
|
||||||
switch (truth.escrow_type) {
|
switch (truth.escrow_type) {
|
||||||
case ChallengeType.Question: {
|
case ChallengeType.Question: {
|
||||||
|
@ -87,10 +87,19 @@ export interface ReducerStateBackup {
|
|||||||
* Currently requested payments.
|
* Currently requested payments.
|
||||||
*
|
*
|
||||||
* List of taler://pay URIs.
|
* List of taler://pay URIs.
|
||||||
|
*
|
||||||
|
* FIXME: There should be more information in this,
|
||||||
|
* including the provider and amount.
|
||||||
*/
|
*/
|
||||||
payments?: string[];
|
payments?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: Why is this not a map from provider to payto?
|
||||||
|
*/
|
||||||
policy_payment_requests?: {
|
policy_payment_requests?: {
|
||||||
|
/**
|
||||||
|
* FIXME: This is not a payto URI, right?!
|
||||||
|
*/
|
||||||
payto: string;
|
payto: string;
|
||||||
provider: string;
|
provider: string;
|
||||||
}[];
|
}[];
|
||||||
@ -100,6 +109,10 @@ export interface ReducerStateBackup {
|
|||||||
expiration?: Timestamp;
|
expiration?: Timestamp;
|
||||||
|
|
||||||
upload_fees?: { fee: AmountString }[];
|
upload_fees?: { fee: AmountString }[];
|
||||||
|
|
||||||
|
// FIXME: The payment secrets and pay URIs should
|
||||||
|
// probably be consolidated into a single field.
|
||||||
|
truth_upload_payment_secrets?: Record<string, string>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthMethod {
|
export interface AuthMethod {
|
||||||
|
Loading…
Reference in New Issue
Block a user