anastasis-core: compute upload fees
This commit is contained in:
parent
83b63d1cc0
commit
fdc36b4fb7
@ -1,13 +1,19 @@
|
|||||||
import {
|
import {
|
||||||
|
AmountJson,
|
||||||
|
AmountLike,
|
||||||
|
Amounts,
|
||||||
AmountString,
|
AmountString,
|
||||||
buildSigPS,
|
buildSigPS,
|
||||||
bytesToString,
|
bytesToString,
|
||||||
Codec,
|
Codec,
|
||||||
codecForAny,
|
codecForAny,
|
||||||
decodeCrock,
|
decodeCrock,
|
||||||
|
Duration,
|
||||||
eddsaSign,
|
eddsaSign,
|
||||||
encodeCrock,
|
encodeCrock,
|
||||||
|
getDurationRemaining,
|
||||||
getRandomBytes,
|
getRandomBytes,
|
||||||
|
getTimestampNow,
|
||||||
hash,
|
hash,
|
||||||
j2s,
|
j2s,
|
||||||
Logger,
|
Logger,
|
||||||
@ -1051,27 +1057,62 @@ async function nextFromAuthenticationsEditing(
|
|||||||
async function updateUploadFees(
|
async function updateUploadFees(
|
||||||
state: ReducerStateBackup,
|
state: ReducerStateBackup,
|
||||||
): Promise<ReducerStateBackup | ReducerStateError> {
|
): Promise<ReducerStateBackup | ReducerStateError> {
|
||||||
for (const prov of state.policy_providers ?? []) {
|
const expiration = state.expiration;
|
||||||
const info = state.authentication_providers![prov.provider_url];
|
if (!expiration) {
|
||||||
if (!("currency" in info)) {
|
return { ...state };
|
||||||
continue;
|
}
|
||||||
|
logger.info("updating upload fees");
|
||||||
|
const feePerCurrency: Record<string, AmountJson> = {};
|
||||||
|
const coveredProviders = new Set<string>();
|
||||||
|
const addFee = (x: AmountLike) => {
|
||||||
|
x = Amounts.jsonifyAmount(x);
|
||||||
|
feePerCurrency[x.currency] = Amounts.add(
|
||||||
|
feePerCurrency[x.currency] ?? Amounts.getZero(x.currency),
|
||||||
|
x,
|
||||||
|
).amount;
|
||||||
|
};
|
||||||
|
const years = Duration.toIntegerYears(Duration.getRemaining(expiration));
|
||||||
|
logger.info(`computing fees for ${years} years`);
|
||||||
|
for (const x of state.policies ?? []) {
|
||||||
|
for (const m of x.methods) {
|
||||||
|
const prov = state.authentication_providers![
|
||||||
|
m.provider
|
||||||
|
] as AuthenticationProviderStatusOk;
|
||||||
|
const authMethod = state.authentication_methods![m.authentication_method];
|
||||||
|
if (!coveredProviders.has(m.provider)) {
|
||||||
|
const annualFee = Amounts.mult(prov.annual_fee, years).amount;
|
||||||
|
logger.info(`adding annual fee ${Amounts.stringify(annualFee)}`);
|
||||||
|
addFee(annualFee);
|
||||||
|
coveredProviders.add(m.provider);
|
||||||
|
}
|
||||||
|
for (const pm of prov.methods) {
|
||||||
|
if (pm.type === authMethod.type) {
|
||||||
|
addFee(pm.usage_fee);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { ...state, upload_fees: [] };
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
upload_fees: Object.values(feePerCurrency).map((x) => ({
|
||||||
|
fee: Amounts.stringify(x),
|
||||||
|
})),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function enterSecret(
|
async function enterSecret(
|
||||||
state: ReducerStateBackup,
|
state: ReducerStateBackup,
|
||||||
args: ActionArgEnterSecret,
|
args: ActionArgEnterSecret,
|
||||||
): Promise<ReducerStateBackup | ReducerStateError> {
|
): Promise<ReducerStateBackup | ReducerStateError> {
|
||||||
return {
|
return updateUploadFees({
|
||||||
...state,
|
...state,
|
||||||
expiration: args.expiration,
|
expiration: args.expiration,
|
||||||
core_secret: {
|
core_secret: {
|
||||||
mime: args.secret.mime ?? "text/plain",
|
mime: args.secret.mime ?? "text/plain",
|
||||||
value: args.secret.value,
|
value: args.secret.value,
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function nextFromChallengeSelecting(
|
async function nextFromChallengeSelecting(
|
||||||
@ -1102,11 +1143,10 @@ async function updateSecretExpiration(
|
|||||||
state: ReducerStateBackup,
|
state: ReducerStateBackup,
|
||||||
args: ActionArgsUpdateExpiration,
|
args: ActionArgsUpdateExpiration,
|
||||||
): Promise<ReducerStateBackup | ReducerStateError> {
|
): Promise<ReducerStateBackup | ReducerStateError> {
|
||||||
// FIXME: implement!
|
return updateUploadFees({
|
||||||
return {
|
|
||||||
...state,
|
...state,
|
||||||
expiration: args.expiration,
|
expiration: args.expiration,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const backupTransitions: Record<
|
const backupTransitions: Record<
|
||||||
|
@ -66,6 +66,7 @@ export interface ReducerStateBackup {
|
|||||||
selected_country?: string;
|
selected_country?: string;
|
||||||
secret_name?: string;
|
secret_name?: string;
|
||||||
policies?: Policy[];
|
policies?: Policy[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Policy providers are providers that we checked to be functional
|
* Policy providers are providers that we checked to be functional
|
||||||
* and that are actually used in policies.
|
* and that are actually used in policies.
|
||||||
@ -82,7 +83,7 @@ export interface ReducerStateBackup {
|
|||||||
|
|
||||||
expiration?: Timestamp;
|
expiration?: Timestamp;
|
||||||
|
|
||||||
upload_fees?: AmountString[];
|
upload_fees?: { fee: AmountString }[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthMethod {
|
export interface AuthMethod {
|
||||||
|
@ -349,7 +349,8 @@ export class Amounts {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static mult(a: AmountJson, n: number): Result {
|
static mult(a: AmountLike, n: number): Result {
|
||||||
|
a = this.jsonifyAmount(a);
|
||||||
if (!Number.isInteger(n)) {
|
if (!Number.isInteger(n)) {
|
||||||
throw Error("amount can only be multipied by an integer");
|
throw Error("amount can only be multipied by an integer");
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,20 @@ export function getDurationRemaining(
|
|||||||
return { d_ms: deadline.t_ms - now.t_ms };
|
return { d_ms: deadline.t_ms - now.t_ms };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace Duration {
|
||||||
|
export const getRemaining = getDurationRemaining;
|
||||||
|
export function toIntegerYears(d: Duration): number {
|
||||||
|
if (typeof d.d_ms !== "number") {
|
||||||
|
throw Error("infinite duration");
|
||||||
|
}
|
||||||
|
return Math.ceil(d.d_ms / 1000 / 60 / 60 / 24 / 365);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace Timestamp {
|
||||||
|
export const min = timestampMin;
|
||||||
|
}
|
||||||
|
|
||||||
export function timestampMin(t1: Timestamp, t2: Timestamp): Timestamp {
|
export function timestampMin(t1: Timestamp, t2: Timestamp): Timestamp {
|
||||||
if (t1.t_ms === "never") {
|
if (t1.t_ms === "never") {
|
||||||
return { t_ms: t2.t_ms };
|
return { t_ms: t2.t_ms };
|
||||||
|
Loading…
Reference in New Issue
Block a user