anastasis-core: support pin-type answers
This commit is contained in:
parent
83622bd65a
commit
6d6679e338
@ -10,6 +10,7 @@ import {
|
||||
crypto_sign_keyPair_fromSeed,
|
||||
stringToBytes,
|
||||
secretbox_open,
|
||||
hash,
|
||||
} from "@gnu-taler/taler-util";
|
||||
import { gzipSync } from "fflate";
|
||||
import { argon2id } from "hash-wasm";
|
||||
@ -283,6 +284,10 @@ export async function coreSecretEncrypt(
|
||||
};
|
||||
}
|
||||
|
||||
export async function pinAnswerHash(pin: number): Promise<SecureAnswerHash> {
|
||||
return encodeCrock(hash(stringToBytes(pin.toString())));
|
||||
}
|
||||
|
||||
export async function secureAnswerHash(
|
||||
answer: string,
|
||||
truthUuid: TruthUuid,
|
||||
|
@ -86,11 +86,19 @@ import {
|
||||
decryptKeyShare,
|
||||
KeyShare,
|
||||
coreSecretRecover,
|
||||
pinAnswerHash,
|
||||
} from "./crypto.js";
|
||||
import { unzlibSync, zlibSync } from "fflate";
|
||||
import { EscrowMethod, RecoveryDocument } from "./recovery-document-types.js";
|
||||
import {
|
||||
ChallengeType,
|
||||
EscrowMethod,
|
||||
RecoveryDocument,
|
||||
} from "./recovery-document-types.js";
|
||||
import { ProviderInfo, suggestPolicies } from "./policy-suggestion.js";
|
||||
import { ChallengeFeedback, ChallengeFeedbackStatus } from "./challenge-feedback-types.js";
|
||||
import {
|
||||
ChallengeFeedback,
|
||||
ChallengeFeedbackStatus,
|
||||
} from "./challenge-feedback-types.js";
|
||||
|
||||
const { fetch } = fetchPonyfill({});
|
||||
|
||||
@ -473,7 +481,7 @@ async function uploadSecret(
|
||||
}
|
||||
|
||||
escrowMethods.push({
|
||||
escrow_type: authMethod.type,
|
||||
escrow_type: authMethod.type as any,
|
||||
instructions: authMethod.instructions,
|
||||
provider_salt: provider.salt,
|
||||
truth_salt: tm.truth_salt,
|
||||
@ -697,11 +705,43 @@ async function requestTruth(
|
||||
const url = new URL(`/truth/${truth.uuid}`, truth.url);
|
||||
|
||||
if (solveRequest) {
|
||||
// FIXME: This isn't correct for non-question truth responses.
|
||||
url.searchParams.set(
|
||||
"response",
|
||||
await secureAnswerHash(solveRequest.answer, truth.uuid, truth.truth_salt),
|
||||
);
|
||||
let respHash: string;
|
||||
switch (truth.escrow_type) {
|
||||
case ChallengeType.Question:
|
||||
if ("answer" in solveRequest) {
|
||||
respHash = await secureAnswerHash(
|
||||
solveRequest.answer,
|
||||
truth.uuid,
|
||||
truth.truth_salt,
|
||||
);
|
||||
} else {
|
||||
throw Error("unsupported answer request");
|
||||
}
|
||||
break;
|
||||
case ChallengeType.Email:
|
||||
case ChallengeType.Sms:
|
||||
case ChallengeType.Post:
|
||||
case ChallengeType.Totp: {
|
||||
if ("answer" in solveRequest) {
|
||||
const s = solveRequest.answer.trim().replace(/^A-/, "");
|
||||
let pin: number;
|
||||
try {
|
||||
pin = Number.parseInt(s);
|
||||
} catch (e) {
|
||||
throw Error("invalid pin format");
|
||||
}
|
||||
respHash = await pinAnswerHash(pin);
|
||||
} else if ("pin" in solveRequest) {
|
||||
respHash = await pinAnswerHash(solveRequest.pin);
|
||||
} else {
|
||||
throw Error("unsupported answer request");
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Error("unsupported challenge type");
|
||||
}
|
||||
url.searchParams.set("response", respHash);
|
||||
}
|
||||
|
||||
const resp = await fetch(url.href, {
|
||||
@ -711,10 +751,14 @@ async function requestTruth(
|
||||
});
|
||||
|
||||
if (resp.status === HttpStatusCode.Ok) {
|
||||
const answerSalt =
|
||||
solveRequest && truth.escrow_type === "question"
|
||||
? solveRequest.answer
|
||||
: undefined;
|
||||
let answerSalt: string | undefined = undefined;
|
||||
if (
|
||||
solveRequest &&
|
||||
truth.escrow_type === "question" &&
|
||||
"answer" in solveRequest
|
||||
) {
|
||||
answerSalt = solveRequest.answer;
|
||||
}
|
||||
|
||||
const userId = await userIdentifierDerive(
|
||||
state.identity_attributes,
|
||||
|
@ -1,5 +1,14 @@
|
||||
import { TruthKey, TruthSalt, TruthUuid } from "./crypto.js";
|
||||
|
||||
export enum ChallengeType {
|
||||
Question = "question",
|
||||
Sms = "sms",
|
||||
Email = "email",
|
||||
Post = "post",
|
||||
Totp = "totp",
|
||||
Iban = "iban",
|
||||
}
|
||||
|
||||
export interface RecoveryDocument {
|
||||
/**
|
||||
* Human-readable name of the secret
|
||||
@ -9,7 +18,7 @@ export interface RecoveryDocument {
|
||||
|
||||
/**
|
||||
* Encrypted core secret.
|
||||
*
|
||||
*
|
||||
* Variable-size length, base32-crock encoded.
|
||||
*/
|
||||
encrypted_core_secret: string;
|
||||
@ -56,7 +65,7 @@ export interface EscrowMethod {
|
||||
/**
|
||||
* Type of the escrow method (e.g. security question, SMS etc.).
|
||||
*/
|
||||
escrow_type: string;
|
||||
escrow_type: ChallengeType;
|
||||
|
||||
/**
|
||||
* UUID of the escrow method.
|
||||
|
@ -312,12 +312,44 @@ export interface ActionArgsSelectChallenge {
|
||||
uuid: string;
|
||||
}
|
||||
|
||||
export type ActionArgsSolveChallengeRequest = SolveChallengeAnswerRequest;
|
||||
export type ActionArgsSolveChallengeRequest =
|
||||
| SolveChallengeAnswerRequest
|
||||
| SolveChallengePinRequest
|
||||
| SolveChallengeHashRequest;
|
||||
|
||||
/**
|
||||
* Answer to a challenge.
|
||||
*
|
||||
* For "question" challenges, this is a string with the answer.
|
||||
*
|
||||
* For "sms" / "email" / "post" this is a numeric code with optionally
|
||||
* the "A-" prefix.
|
||||
*/
|
||||
export interface SolveChallengeAnswerRequest {
|
||||
answer: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer to a challenge that requires a numeric response.
|
||||
*
|
||||
* XXX: Should be deprecated in favor of just "answer".
|
||||
*/
|
||||
export interface SolveChallengePinRequest {
|
||||
pin: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Answer to a challenge by directly providing the hash.
|
||||
*
|
||||
* XXX: When / why is this even used?
|
||||
*/
|
||||
export interface SolveChallengeHashRequest {
|
||||
/**
|
||||
* Base32-crock encoded hash code.
|
||||
*/
|
||||
hash: string;
|
||||
}
|
||||
|
||||
export interface PolicyMember {
|
||||
authentication_method: number;
|
||||
provider: string;
|
||||
|
Loading…
Reference in New Issue
Block a user