aboutsummaryrefslogtreecommitdiff
path: root/packages
diff options
context:
space:
mode:
authorFlorian Dold <florian@dold.me>2021-11-02 17:02:04 +0100
committerFlorian Dold <florian@dold.me>2021-11-02 17:02:14 +0100
commitfdc36b4fb75201e23023a583b8eebd05b1f24f77 (patch)
tree828fdd4cd2e80dcbd170211f8babff1adf096279 /packages
parent83b63d1cc076dced82a235d7ca37ff04357ddb73 (diff)
anastasis-core: compute upload fees
Diffstat (limited to 'packages')
-rw-r--r--packages/anastasis-core/src/index.ts60
-rw-r--r--packages/anastasis-core/src/reducer-types.ts3
-rw-r--r--packages/taler-util/src/amounts.ts3
-rw-r--r--packages/taler-util/src/time.ts14
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 };