diff options
author | Florian Dold <florian@dold.me> | 2021-11-02 17:02:04 +0100 |
---|---|---|
committer | Florian Dold <florian@dold.me> | 2021-11-02 17:02:14 +0100 |
commit | fdc36b4fb75201e23023a583b8eebd05b1f24f77 (patch) | |
tree | 828fdd4cd2e80dcbd170211f8babff1adf096279 /packages | |
parent | 83b63d1cc076dced82a235d7ca37ff04357ddb73 (diff) |
anastasis-core: compute upload fees
Diffstat (limited to 'packages')
-rw-r--r-- | packages/anastasis-core/src/index.ts | 60 | ||||
-rw-r--r-- | packages/anastasis-core/src/reducer-types.ts | 3 | ||||
-rw-r--r-- | packages/taler-util/src/amounts.ts | 3 | ||||
-rw-r--r-- | packages/taler-util/src/time.ts | 14 |
4 files changed, 68 insertions, 12 deletions
diff --git a/packages/anastasis-core/src/index.ts b/packages/anastasis-core/src/index.ts index 07f8122e3..9bb4e347a 100644 --- a/packages/anastasis-core/src/index.ts +++ b/packages/anastasis-core/src/index.ts @@ -1,13 +1,19 @@ import { + AmountJson, + AmountLike, + Amounts, AmountString, buildSigPS, bytesToString, Codec, codecForAny, decodeCrock, + Duration, eddsaSign, encodeCrock, + getDurationRemaining, getRandomBytes, + getTimestampNow, hash, j2s, Logger, @@ -1051,27 +1057,62 @@ async function nextFromAuthenticationsEditing( async function updateUploadFees( state: ReducerStateBackup, ): Promise<ReducerStateBackup | ReducerStateError> { - for (const prov of state.policy_providers ?? []) { - const info = state.authentication_providers![prov.provider_url]; - if (!("currency" in info)) { - continue; + const expiration = state.expiration; + if (!expiration) { + return { ...state }; + } + 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( state: ReducerStateBackup, args: ActionArgEnterSecret, ): Promise<ReducerStateBackup | ReducerStateError> { - return { + return updateUploadFees({ ...state, expiration: args.expiration, core_secret: { mime: args.secret.mime ?? "text/plain", value: args.secret.value, }, - }; + }); } async function nextFromChallengeSelecting( @@ -1102,11 +1143,10 @@ async function updateSecretExpiration( state: ReducerStateBackup, args: ActionArgsUpdateExpiration, ): Promise<ReducerStateBackup | ReducerStateError> { - // FIXME: implement! - return { + return updateUploadFees({ ...state, expiration: args.expiration, - }; + }); } const backupTransitions: Record< diff --git a/packages/anastasis-core/src/reducer-types.ts b/packages/anastasis-core/src/reducer-types.ts index 03883ce17..2f0d324ae 100644 --- a/packages/anastasis-core/src/reducer-types.ts +++ b/packages/anastasis-core/src/reducer-types.ts @@ -66,6 +66,7 @@ export interface ReducerStateBackup { selected_country?: string; secret_name?: string; policies?: Policy[]; + /** * Policy providers are providers that we checked to be functional * and that are actually used in policies. @@ -82,7 +83,7 @@ export interface ReducerStateBackup { expiration?: Timestamp; - upload_fees?: AmountString[]; + upload_fees?: { fee: AmountString }[]; } export interface AuthMethod { diff --git a/packages/taler-util/src/amounts.ts b/packages/taler-util/src/amounts.ts index 5a8c7f06f..41fd14bee 100644 --- a/packages/taler-util/src/amounts.ts +++ b/packages/taler-util/src/amounts.ts @@ -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)) { throw Error("amount can only be multipied by an integer"); } diff --git a/packages/taler-util/src/time.ts b/packages/taler-util/src/time.ts index c0858ada6..856db8a57 100644 --- a/packages/taler-util/src/time.ts +++ b/packages/taler-util/src/time.ts @@ -69,6 +69,20 @@ export function getDurationRemaining( 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 { if (t1.t_ms === "never") { return { t_ms: t2.t_ms }; |