gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated (082bef33 -> 04356cd2)


From: gnunet
Subject: [taler-wallet-core] branch master updated (082bef33 -> 04356cd2)
Date: Wed, 03 Nov 2021 13:35:04 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a change to branch master
in repository wallet-core.

    from 082bef33 anastasis-core: maximize diversity in provider selection
     new ab6fd6c8 move HTTP status codes to taler-util
     new 04356cd2 anastasis: refactor feedback types

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../anastasis-core/src/challenge-feedback-types.ts | 149 ++++++++
 packages/anastasis-core/src/index.ts               | 150 ++++----
 packages/anastasis-core/src/reducer-types.ts       |  35 +-
 packages/taler-util/src/http-status-codes.ts       | 379 +++++++++++++++++++++
 packages/taler-util/src/index.ts                   |   1 +
 .../src/operations/backup/index.ts                 |  10 +-
 packages/taler-wallet-core/src/operations/pay.ts   |   6 +-
 .../taler-wallet-core/src/operations/refresh.ts    |   5 +-
 packages/taler-wallet-core/src/util/http.ts        |  11 -
 9 files changed, 639 insertions(+), 107 deletions(-)
 create mode 100644 packages/anastasis-core/src/challenge-feedback-types.ts
 create mode 100644 packages/taler-util/src/http-status-codes.ts

diff --git a/packages/anastasis-core/src/challenge-feedback-types.ts 
b/packages/anastasis-core/src/challenge-feedback-types.ts
new file mode 100644
index 00000000..d6a2e3e8
--- /dev/null
+++ b/packages/anastasis-core/src/challenge-feedback-types.ts
@@ -0,0 +1,149 @@
+import { AmountString, HttpStatusCode } from "@gnu-taler/taler-util";
+
+export enum ChallengeFeedbackStatus {
+  Solved = "solved",
+  ServerFailure = "server-failure",
+  TruthUnknown = "truth-unknown",
+  Redirect = "redirect",
+  Payment = "payment",
+  Pending = "pending",
+  Message = "message",
+  Unsupported = "unsupported",
+  RateLimitExceeded = "rate-limit-exceeded",
+  AuthIban = "auth-iban",
+}
+
+export type ChallengeFeedback =
+  | ChallengeFeedbackSolved
+  | ChallengeFeedbackPending
+  | ChallengeFeedbackPayment
+  | ChallengeFeedbackServerFailure
+  | ChallengeFeedbackRateLimitExceeded
+  | ChallengeFeedbackTruthUnknown
+  | ChallengeFeedbackRedirect
+  | ChallengeFeedbackMessage
+  | ChallengeFeedbackUnsupported
+  | ChallengeFeedbackAuthIban;
+
+/**
+ * Challenge has been solved and the key share has
+ * been retrieved.
+ */
+export interface ChallengeFeedbackSolved {
+  state: ChallengeFeedbackStatus.Solved;
+}
+
+/**
+ * The challenge given by the server is unsupported
+ * by the current anastasis client.
+ */
+export interface ChallengeFeedbackUnsupported {
+  state: ChallengeFeedbackStatus.Unsupported;
+  http_status: HttpStatusCode;
+  /**
+   * Human-readable identifier of the unsupported method.
+   */
+  unsupported_method: string;
+}
+
+/**
+ * The user tried to answer too often with a wrong answer.
+ */
+export interface ChallengeFeedbackRateLimitExceeded {
+  state: ChallengeFeedbackStatus.RateLimitExceeded;
+}
+
+/**
+ * Instructions for performing authentication via an
+ * IBAN bank transfer.
+ */
+export interface ChallengeFeedbackAuthIban {
+  state: ChallengeFeedbackStatus.AuthIban;
+
+  /**
+   * Amount that should be transfered for a successful authentication.
+   */
+  challenge_amount: AmountString;
+
+  /**
+   * Account that should be credited.
+   */
+  credit_iban: string;
+
+  /**
+   * Creditor name.
+   */
+  business_name: string;
+
+  /**
+   * Unstructured remittance information that should
+   * be contained in the bank transfer.
+   */
+  wire_transfer_subject: string;
+}
+
+/**
+ * Challenge still needs to be solved.
+ */
+export interface ChallengeFeedbackPending {
+  state: ChallengeFeedbackStatus.Pending;
+}
+
+/**
+ * Human-readable response from the provider
+ * after the user failed to solve the challenge
+ * correctly.
+ */
+export interface ChallengeFeedbackMessage {
+  state: ChallengeFeedbackStatus.Message;
+  message: string;
+}
+
+/**
+ * The server experienced a temporary failure.
+ */
+export interface ChallengeFeedbackServerFailure {
+  state: ChallengeFeedbackStatus.ServerFailure;
+  http_status: HttpStatusCode | 0;
+
+  /**
+   * Taler-style error response, if available.
+   */
+  error_response?: any;
+}
+
+/**
+ * The truth is unknown to the provider.  There
+ * is no reason to continue trying to solve any
+ * challenges in the policy.
+ */
+export interface ChallengeFeedbackTruthUnknown {
+  state: ChallengeFeedbackStatus.TruthUnknown;
+}
+
+/**
+ * The user should be asked to go to a URL
+ * to complete the authentication there.
+ */
+export interface ChallengeFeedbackRedirect {
+  state: ChallengeFeedbackStatus.Redirect;
+  http_status: number;
+  redirect_url: string;
+}
+
+/**
+ * A payment is required before the user can
+ * even attempt to solve the challenge.
+ */
+export interface ChallengeFeedbackPayment {
+  state: ChallengeFeedbackStatus.Payment;
+
+  taler_pay_uri: string;
+
+  provider: string;
+
+  /**
+   * FIXME: Why is this required?!
+   */
+  payment_secret: string;
+}
diff --git a/packages/anastasis-core/src/index.ts 
b/packages/anastasis-core/src/index.ts
index db99db61..859dd083 100644
--- a/packages/anastasis-core/src/index.ts
+++ b/packages/anastasis-core/src/index.ts
@@ -11,10 +11,9 @@ import {
   Duration,
   eddsaSign,
   encodeCrock,
-  getDurationRemaining,
   getRandomBytes,
-  getTimestampNow,
   hash,
+  HttpStatusCode,
   j2s,
   Logger,
   stringToBytes,
@@ -91,6 +90,7 @@ import {
 import { unzlibSync, zlibSync } from "fflate";
 import { EscrowMethod, RecoveryDocument } from "./recovery-document-types.js";
 import { ProviderInfo, suggestPolicies } from "./policy-suggestion.js";
+import { ChallengeFeedback, ChallengeFeedbackStatus } from 
"./challenge-feedback-types.js";
 
 const { fetch } = fetchPonyfill({});
 
@@ -291,7 +291,6 @@ async function backupEnterUserAttributes(
   return newState;
 }
 
-
 /**
  * Truth data as stored in the reducer.
  */
@@ -551,6 +550,7 @@ async function uploadSecret(
 
   return {
     ...state,
+    core_secret: undefined,
     backup_state: BackupStates.BackupFinished,
     success_details: successDetails,
   };
@@ -684,25 +684,24 @@ async function tryRecoverSecret(
   return { ...state };
 }
 
-async function solveChallenge(
+/**
+ * Request a truth, optionally with a challenge solution
+ * provided by the user.
+ */
+async function requestTruth(
   state: ReducerStateRecovery,
-  ta: ActionArgsSolveChallengeRequest,
+  truth: EscrowMethod,
+  solveRequest?: ActionArgsSolveChallengeRequest,
 ): Promise<ReducerStateRecovery | ReducerStateError> {
-  const recDoc: RecoveryDocument = state.verbatim_recovery_document!;
-  const truth = recDoc.escrow_methods.find(
-    (x) => x.uuid === state.selected_challenge_uuid,
-  );
-  if (!truth) {
-    throw "truth for challenge not found";
-  }
-
   const url = new URL(`/truth/${truth.uuid}`, truth.url);
 
-  // FIXME: This isn't correct for non-question truth responses.
-  url.searchParams.set(
-    "response",
-    await secureAnswerHash(ta.answer, truth.uuid, truth.truth_salt),
-  );
+  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),
+    );
+  }
 
   const resp = await fetch(url.href, {
     headers: {
@@ -710,48 +709,79 @@ async function solveChallenge(
     },
   });
 
-  if (resp.status !== 200) {
-    return {
-      code: TalerErrorCode.ANASTASIS_TRUTH_CHALLENGE_FAILED,
-      hint: "got non-200 response",
-      http_status: resp.status,
-    } as ReducerStateError;
-  }
+  if (resp.status === HttpStatusCode.Ok) {
+    const answerSalt =
+      solveRequest && truth.escrow_type === "question"
+        ? solveRequest.answer
+        : undefined;
 
-  const answerSalt = truth.escrow_type === "question" ? ta.answer : undefined;
+    const userId = await userIdentifierDerive(
+      state.identity_attributes,
+      truth.provider_salt,
+    );
 
-  const userId = await userIdentifierDerive(
-    state.identity_attributes,
-    truth.provider_salt,
-  );
+    const respBody = new Uint8Array(await resp.arrayBuffer());
+    const keyShare = await decryptKeyShare(
+      encodeCrock(respBody),
+      userId,
+      answerSalt,
+    );
 
-  const respBody = new Uint8Array(await resp.arrayBuffer());
-  const keyShare = await decryptKeyShare(
-    encodeCrock(respBody),
-    userId,
-    answerSalt,
-  );
+    const recoveredKeyShares = {
+      ...(state.recovered_key_shares ?? {}),
+      [truth.uuid]: keyShare,
+    };
 
-  const recoveredKeyShares = {
-    ...(state.recovered_key_shares ?? {}),
-    [truth.uuid]: keyShare,
-  };
+    const challengeFeedback: { [x: string]: ChallengeFeedback } = {
+      ...state.challenge_feedback,
+      [truth.uuid]: {
+        state: ChallengeFeedbackStatus.Solved,
+      },
+    };
 
-  const challengeFeedback = {
-    ...state.challenge_feedback,
-    [truth.uuid]: {
-      state: "solved",
-    },
-  };
+    const newState: ReducerStateRecovery = {
+      ...state,
+      recovery_state: RecoveryStates.ChallengeSelecting,
+      challenge_feedback: challengeFeedback,
+      recovered_key_shares: recoveredKeyShares,
+    };
 
-  const newState: ReducerStateRecovery = {
-    ...state,
-    recovery_state: RecoveryStates.ChallengeSelecting,
-    challenge_feedback: challengeFeedback,
-    recovered_key_shares: recoveredKeyShares,
-  };
+    return tryRecoverSecret(newState);
+  }
+
+  if (resp.status === HttpStatusCode.Forbidden) {
+    return {
+      ...state,
+      recovery_state: RecoveryStates.ChallengeSolving,
+      challenge_feedback: {
+        ...state.challenge_feedback,
+        [truth.uuid]: {
+          state: ChallengeFeedbackStatus.Message,
+          message: "Challenge should be solved",
+        },
+      },
+    };
+  }
 
-  return tryRecoverSecret(newState);
+  return {
+    code: TalerErrorCode.ANASTASIS_TRUTH_CHALLENGE_FAILED,
+    hint: "got unexpected /truth/ response status",
+    http_status: resp.status,
+  } as ReducerStateError;
+}
+
+async function solveChallenge(
+  state: ReducerStateRecovery,
+  ta: ActionArgsSolveChallengeRequest,
+): Promise<ReducerStateRecovery | ReducerStateError> {
+  const recDoc: RecoveryDocument = state.verbatim_recovery_document!;
+  const truth = recDoc.escrow_methods.find(
+    (x) => x.uuid === state.selected_challenge_uuid,
+  );
+  if (!truth) {
+    throw Error("truth for challenge not found");
+  }
+  return requestTruth(state, truth, ta);
 }
 
 async function recoveryEnterUserAttributes(
@@ -776,19 +806,7 @@ async function selectChallenge(
     throw "truth for challenge not found";
   }
 
-  const url = new URL(`/truth/${truth.uuid}`, truth.url);
-
-  const resp = await fetch(url.href, {
-    headers: {
-      "Anastasis-Truth-Decryption-Key": truth.truth_key,
-    },
-  });
-
-  return {
-    ...state,
-    recovery_state: RecoveryStates.ChallengeSolving,
-    selected_challenge_uuid: ta.uuid,
-  };
+  return requestTruth({ ...state, selected_challenge_uuid: ta.uuid }, truth);
 }
 
 async function backupSelectContinent(
diff --git a/packages/anastasis-core/src/reducer-types.ts 
b/packages/anastasis-core/src/reducer-types.ts
index 94826870..69feb6b6 100644
--- a/packages/anastasis-core/src/reducer-types.ts
+++ b/packages/anastasis-core/src/reducer-types.ts
@@ -8,6 +8,7 @@ import {
   codecForTimestamp,
   Timestamp,
 } from "@gnu-taler/taler-util";
+import { ChallengeFeedback } from "./challenge-feedback-types.js";
 import { KeyShare } from "./crypto.js";
 import { RecoveryDocument } from "./recovery-document-types.js";
 
@@ -185,10 +186,6 @@ export interface ReducerStateRecovery {
   authentication_providers?: { [url: string]: AuthenticationProviderStatus };
 }
 
-export interface ChallengeFeedback {
-  state: string;
-}
-
 export interface ReducerStateError {
   backup_state?: undefined;
   recovery_state?: undefined;
@@ -311,21 +308,10 @@ export interface ActionArgSelectCountry {
   currencies: string[];
 }
 
-export const codecForActionArgSelectCountry = () =>
-  buildCodecForObject<ActionArgSelectCountry>()
-    .property("country_code", codecForString())
-    .property("currencies", codecForList(codecForString()))
-    .build("ActionArgSelectCountry");
-
 export interface ActionArgsSelectChallenge {
   uuid: string;
 }
 
-export const codecForActionArgSelectChallenge = () =>
-  buildCodecForObject<ActionArgsSelectChallenge>()
-    .property("uuid", codecForString())
-    .build("ActionArgSelectChallenge");
-
 export type ActionArgsSolveChallengeRequest = SolveChallengeAnswerRequest;
 
 export interface SolveChallengeAnswerRequest {
@@ -341,6 +327,10 @@ export interface ActionArgsAddPolicy {
   policy: PolicyMember[];
 }
 
+export interface ActionArgsUpdateExpiration {
+  expiration: Timestamp;
+}
+
 export const codecForPolicyMember = () =>
   buildCodecForObject<PolicyMember>()
     .property("authentication_method", codecForNumber())
@@ -352,11 +342,18 @@ export const codecForActionArgsAddPolicy = () =>
     .property("policy", codecForList(codecForPolicyMember()))
     .build("ActionArgsAddPolicy");
 
-export interface ActionArgsUpdateExpiration {
-  expiration: Timestamp;
-}
-
 export const codecForActionArgsUpdateExpiration = () =>
   buildCodecForObject<ActionArgsUpdateExpiration>()
     .property("expiration", codecForTimestamp)
     .build("ActionArgsUpdateExpiration");
+
+export const codecForActionArgSelectChallenge = () =>
+  buildCodecForObject<ActionArgsSelectChallenge>()
+    .property("uuid", codecForString())
+    .build("ActionArgSelectChallenge");
+
+export const codecForActionArgSelectCountry = () =>
+  buildCodecForObject<ActionArgSelectCountry>()
+    .property("country_code", codecForString())
+    .property("currencies", codecForList(codecForString()))
+    .build("ActionArgSelectCountry");
diff --git a/packages/taler-util/src/http-status-codes.ts 
b/packages/taler-util/src/http-status-codes.ts
new file mode 100644
index 00000000..84883999
--- /dev/null
+++ b/packages/taler-util/src/http-status-codes.ts
@@ -0,0 +1,379 @@
+/**
+ * Hypertext Transfer Protocol (HTTP) response status codes.
+ *
+ * @see {@link https://en.wikipedia.org/wiki/List_of_HTTP_status_codes}
+ */
+export enum HttpStatusCode {
+  /**
+   * The server has received the request headers and the client should proceed 
to send the request body
+   * (in the case of a request for which a body needs to be sent; for example, 
a POST request).
+   * Sending a large request body to a server after a request has been 
rejected for inappropriate headers would be inefficient.
+   * To have a server check the request's headers, a client must send Expect: 
100-continue as a header in its initial request
+   * and receive a 100 Continue status code in response before sending the 
body. The response 417 Expectation Failed indicates the request should not be 
continued.
+   */
+  Continue = 100,
+
+  /**
+   * The requester has asked the server to switch protocols and the server has 
agreed to do so.
+   */
+  SwitchingProtocols = 101,
+
+  /**
+   * A WebDAV request may contain many sub-requests involving file operations, 
requiring a long time to complete the request.
+   * This code indicates that the server has received and is processing the 
request, but no response is available yet.
+   * This prevents the client from timing out and assuming the request was 
lost.
+   */
+  Processing = 102,
+
+  /**
+   * Standard response for successful HTTP requests.
+   * The actual response will depend on the request method used.
+   * In a GET request, the response will contain an entity corresponding to 
the requested resource.
+   * In a POST request, the response will contain an entity describing or 
containing the result of the action.
+   */
+  Ok = 200,
+
+  /**
+   * The request has been fulfilled, resulting in the creation of a new 
resource.
+   */
+  Created = 201,
+
+  /**
+   * The request has been accepted for processing, but the processing has not 
been completed.
+   * The request might or might not be eventually acted upon, and may be 
disallowed when processing occurs.
+   */
+  Accepted = 202,
+
+  /**
+   * SINCE HTTP/1.1
+   * The server is a transforming proxy that received a 200 OK from its origin,
+   * but is returning a modified version of the origin's response.
+   */
+  NonAuthoritativeInformation = 203,
+
+  /**
+   * The server successfully processed the request and is not returning any 
content.
+   */
+  NoContent = 204,
+
+  /**
+   * The server successfully processed the request, but is not returning any 
content.
+   * Unlike a 204 response, this response requires that the requester reset 
the document view.
+   */
+  ResetContent = 205,
+
+  /**
+   * The server is delivering only part of the resource (byte serving) due to 
a range header sent by the client.
+   * The range header is used by HTTP clients to enable resuming of 
interrupted downloads,
+   * or split a download into multiple simultaneous streams.
+   */
+  PartialContent = 206,
+
+  /**
+   * The message body that follows is an XML message and can contain a number 
of separate response codes,
+   * depending on how many sub-requests were made.
+   */
+  MultiStatus = 207,
+
+  /**
+   * The members of a DAV binding have already been enumerated in a preceding 
part of the (multistatus) response,
+   * and are not being included again.
+   */
+  AlreadyReported = 208,
+
+  /**
+   * The server has fulfilled a request for the resource,
+   * and the response is a representation of the result of one or more 
instance-manipulations applied to the current instance.
+   */
+  ImUsed = 226,
+
+  /**
+   * Indicates multiple options for the resource from which the client may 
choose (via agent-driven content negotiation).
+   * For example, this code could be used to present multiple video format 
options,
+   * to list files with different filename extensions, or to suggest 
word-sense disambiguation.
+   */
+  MultipleChoices = 300,
+
+  /**
+   * This and all future requests should be directed to the given URI.
+   */
+  MovedPermanently = 301,
+
+  /**
+   * This is an example of industry practice contradicting the standard.
+   * The HTTP/1.0 specification (RFC 1945) required the client to perform a 
temporary redirect
+   * (the original describing phrase was "Moved Temporarily"), but popular 
browsers implemented 302
+   * with the functionality of a 303 See Other. Therefore, HTTP/1.1 added 
status codes 303 and 307
+   * to distinguish between the two behaviours. However, some Web applications 
and frameworks
+   * use the 302 status code as if it were the 303.
+   */
+  Found = 302,
+
+  /**
+   * SINCE HTTP/1.1
+   * The response to the request can be found under another URI using a GET 
method.
+   * When received in response to a POST (or PUT/DELETE), the client should 
presume that
+   * the server has received the data and should issue a redirect with a 
separate GET message.
+   */
+  SeeOther = 303,
+
+  /**
+   * Indicates that the resource has not been modified since the version 
specified by the request headers If-Modified-Since or If-None-Match.
+   * In such case, there is no need to retransmit the resource since the 
client still has a previously-downloaded copy.
+   */
+  NotModified = 304,
+
+  /**
+   * SINCE HTTP/1.1
+   * The requested resource is available only through a proxy, the address for 
which is provided in the response.
+   * Many HTTP clients (such as Mozilla and Internet Explorer) do not 
correctly handle responses with this status code, primarily for security 
reasons.
+   */
+  UseProxy = 305,
+
+  /**
+   * No longer used. Originally meant "Subsequent requests should use the 
specified proxy."
+   */
+  SwitchProxy = 306,
+
+  /**
+   * SINCE HTTP/1.1
+   * In this case, the request should be repeated with another URI; however, 
future requests should still use the original URI.
+   * In contrast to how 302 was historically implemented, the request method 
is not allowed to be changed when reissuing the original request.
+   * For example, a POST request should be repeated using another POST request.
+   */
+  TemporaryRedirect = 307,
+
+  /**
+   * The request and all future requests should be repeated using another URI.
+   * 307 and 308 parallel the behaviors of 302 and 301, but do not allow the 
HTTP method to change.
+   * So, for example, submitting a form to a permanently redirected resource 
may continue smoothly.
+   */
+  PermanentRedirect = 308,
+
+  /**
+   * The server cannot or will not process the request due to an apparent 
client error
+   * (e.g., malformed request syntax, too large size, invalid request message 
framing, or deceptive request routing).
+   */
+  BadRequest = 400,
+
+  /**
+   * Similar to 403 Forbidden, but specifically for use when authentication is 
required and has failed or has not yet
+   * been provided. The response must include a WWW-Authenticate header field 
containing a challenge applicable to the
+   * requested resource. See Basic access authentication and Digest access 
authentication. 401 semantically means
+   * "unauthenticated",i.e. the user does not have the necessary credentials.
+   */
+  Unauthorized = 401,
+
+  /**
+   * Reserved for future use. The original intention was that this code might 
be used as part of some form of digital
+   * cash or micro payment scheme, but that has not happened, and this code is 
not usually used.
+   * Google Developers API uses this status if a particular developer has 
exceeded the daily limit on requests.
+   */
+  PaymentRequired = 402,
+
+  /**
+   * The request was valid, but the server is refusing action.
+   * The user might not have the necessary permissions for a resource.
+   */
+  Forbidden = 403,
+
+  /**
+   * The requested resource could not be found but may be available in the 
future.
+   * Subsequent requests by the client are permissible.
+   */
+  NotFound = 404,
+
+  /**
+   * A request method is not supported for the requested resource;
+   * for example, a GET request on a form that requires data to be presented 
via POST, or a PUT request on a read-only resource.
+   */
+  MethodNotAllowed = 405,
+
+  /**
+   * The requested resource is capable of generating only content not 
acceptable according to the Accept headers sent in the request.
+   */
+  NotAcceptable = 406,
+
+  /**
+   * The client must first authenticate itself with the proxy.
+   */
+  ProxyAuthenticationRequired = 407,
+
+  /**
+   * The server timed out waiting for the request.
+   * According to HTTP specifications:
+   * "The client did not produce a request within the time that the server was 
prepared to wait. The client MAY repeat the request without modifications at 
any later time."
+   */
+  RequestTimeout = 408,
+
+  /**
+   * Indicates that the request could not be processed because of conflict in 
the request,
+   * such as an edit conflict between multiple simultaneous updates.
+   */
+  Conflict = 409,
+
+  /**
+   * Indicates that the resource requested is no longer available and will not 
be available again.
+   * This should be used when a resource has been intentionally removed and 
the resource should be purged.
+   * Upon receiving a 410 status code, the client should not request the 
resource in the future.
+   * Clients such as search engines should remove the resource from their 
indices.
+   * Most use cases do not require clients and search engines to purge the 
resource, and a "404 Not Found" may be used instead.
+   */
+  Gone = 410,
+
+  /**
+   * The request did not specify the length of its content, which is required 
by the requested resource.
+   */
+  LengthRequired = 411,
+
+  /**
+   * The server does not meet one of the preconditions that the requester put 
on the request.
+   */
+  PreconditionFailed = 412,
+
+  /**
+   * The request is larger than the server is willing or able to process. 
Previously called "Request Entity Too Large".
+   */
+  PayloadTooLarge = 413,
+
+  /**
+   * The URI provided was too long for the server to process. Often the result 
of too much data being encoded as a query-string of a GET request,
+   * in which case it should be converted to a POST request.
+   * Called "Request-URI Too Long" previously.
+   */
+  UriTooLong = 414,
+
+  /**
+   * The request entity has a media type which the server or resource does not 
support.
+   * For example, the client uploads an image as image/svg+xml, but the server 
requires that images use a different format.
+   */
+  UnsupportedMediaType = 415,
+
+  /**
+   * The client has asked for a portion of the file (byte serving), but the 
server cannot supply that portion.
+   * For example, if the client asked for a part of the file that lies beyond 
the end of the file.
+   * Called "Requested Range Not Satisfiable" previously.
+   */
+  RangeNotSatisfiable = 416,
+
+  /**
+   * The server cannot meet the requirements of the Expect request-header 
field.
+   */
+  ExpectationFailed = 417,
+
+  /**
+   * This code was defined in 1998 as one of the traditional IETF April Fools' 
jokes, in RFC 2324, Hyper Text Coffee Pot Control Protocol,
+   * and is not expected to be implemented by actual HTTP servers. The RFC 
specifies this code should be returned by
+   * teapots requested to brew coffee. This HTTP status is used as an Easter 
egg in some websites, including Google.com.
+   */
+  IAmATeapot = 418,
+
+  /**
+   * The request was directed at a server that is not able to produce a 
response (for example because a connection reuse).
+   */
+  MisdirectedRequest = 421,
+
+  /**
+   * The request was well-formed but was unable to be followed due to semantic 
errors.
+   */
+  UnprocessableEntity = 422,
+
+  /**
+   * The resource that is being accessed is locked.
+   */
+  Locked = 423,
+
+  /**
+   * The request failed due to failure of a previous request (e.g., a 
PROPPATCH).
+   */
+  FailedDependency = 424,
+
+  /**
+   * The client should switch to a different protocol such as TLS/1.0, given 
in the Upgrade header field.
+   */
+  UpgradeRequired = 426,
+
+  /**
+   * The origin server requires the request to be conditional.
+   * Intended to prevent "the 'lost update' problem, where a client
+   * GETs a resource's state, modifies it, and PUTs it back to the server,
+   * when meanwhile a third party has modified the state on the server, 
leading to a conflict."
+   */
+  PreconditionRequired = 428,
+
+  /**
+   * The user has sent too many requests in a given amount of time. Intended 
for use with rate-limiting schemes.
+   */
+  TooManyRequests = 429,
+
+  /**
+   * The server is unwilling to process the request because either an 
individual header field,
+   * or all the header fields collectively, are too large.
+   */
+  RequestHeaderFieldsTooLarge = 431,
+
+  /**
+   * A server operator has received a legal demand to deny access to a 
resource or to a set of resources
+   * that includes the requested resource. The code 451 was chosen as a 
reference to the novel Fahrenheit 451.
+   */
+  UnavailableForLegalReasons = 451,
+
+  /**
+   * A generic error message, given when an unexpected condition was 
encountered and no more specific message is suitable.
+   */
+  InternalServerError = 500,
+
+  /**
+   * The server either does not recognize the request method, or it lacks the 
ability to fulfill the request.
+   * Usually this implies future availability (e.g., a new feature of a 
web-service API).
+   */
+  NotImplemented = 501,
+
+  /**
+   * The server was acting as a gateway or proxy and received an invalid 
response from the upstream server.
+   */
+  BadGateway = 502,
+
+  /**
+   * The server is currently unavailable (because it is overloaded or down for 
maintenance).
+   * Generally, this is a temporary state.
+   */
+  ServiceUnavailable = 503,
+
+  /**
+   * The server was acting as a gateway or proxy and did not receive a timely 
response from the upstream server.
+   */
+  GatewayTimeout = 504,
+
+  /**
+   * The server does not support the HTTP protocol version used in the request
+   */
+  HttpVersionNotSupported = 505,
+
+  /**
+   * Transparent content negotiation for the request results in a circular 
reference.
+   */
+  VariantAlsoNegotiates = 506,
+
+  /**
+   * The server is unable to store the representation needed to complete the 
request.
+   */
+  InsufficientStorage = 507,
+
+  /**
+   * The server detected an infinite loop while processing the request.
+   */
+  LoopDetected = 508,
+
+  /**
+   * Further extensions to the request are required for the server to fulfill 
it.
+   */
+  NotExtended = 510,
+
+  /**
+   * The client needs to authenticate to gain network access.
+   * Intended for use by intercepting proxies used to control access to the 
network (e.g., "captive portals" used
+   * to require agreement to Terms of Service before granting full Internet 
access via a Wi-Fi hotspot).
+   */
+  NetworkAuthenticationRequired = 511,
+}
diff --git a/packages/taler-util/src/index.ts b/packages/taler-util/src/index.ts
index 4ad75295..c42e5e66 100644
--- a/packages/taler-util/src/index.ts
+++ b/packages/taler-util/src/index.ts
@@ -22,6 +22,7 @@ export * from "./url.js";
 export { fnutil } from "./fnutils.js";
 export * from "./kdf.js";
 export * from "./talerCrypto.js";
+export * from "./http-status-codes.js";
 export {
   randomBytes,
   secretbox,
diff --git a/packages/taler-wallet-core/src/operations/backup/index.ts 
b/packages/taler-wallet-core/src/operations/backup/index.ts
index 913ffcb2..3f4c0227 100644
--- a/packages/taler-wallet-core/src/operations/backup/index.ts
+++ b/packages/taler-wallet-core/src/operations/backup/index.ts
@@ -40,6 +40,7 @@ import {
   ConfirmPayResultType,
   durationFromSpec,
   getTimestampNow,
+  HttpStatusCode,
   j2s,
   Logger,
   notEmpty,
@@ -84,7 +85,6 @@ import {
 } from "../../db.js";
 import { guardOperationException } from "../../errors.js";
 import {
-  HttpResponseStatus,
   readSuccessResponseJsonOrThrow,
   readTalerErrorResponse,
 } from "../../util/http.js";
@@ -317,7 +317,7 @@ async function runBackupCycleForProvider(
 
   logger.trace(`sync response status: ${resp.status}`);
 
-  if (resp.status === HttpResponseStatus.NotModified) {
+  if (resp.status === HttpStatusCode.NotModified) {
     await ws.db
       .mktx((x) => ({ backupProvider: x.backupProviders }))
       .runReadWrite(async (tx) => {
@@ -335,7 +335,7 @@ async function runBackupCycleForProvider(
     return;
   }
 
-  if (resp.status === HttpResponseStatus.PaymentRequired) {
+  if (resp.status === HttpStatusCode.PaymentRequired) {
     logger.trace("payment required for backup");
     logger.trace(`headers: ${j2s(resp.headers)}`);
     const talerUri = resp.headers.get("taler");
@@ -396,7 +396,7 @@ async function runBackupCycleForProvider(
     return;
   }
 
-  if (resp.status === HttpResponseStatus.NoContent) {
+  if (resp.status === HttpStatusCode.NoContent) {
     await ws.db
       .mktx((x) => ({ backupProviders: x.backupProviders }))
       .runReadWrite(async (tx) => {
@@ -415,7 +415,7 @@ async function runBackupCycleForProvider(
     return;
   }
 
-  if (resp.status === HttpResponseStatus.Conflict) {
+  if (resp.status === HttpStatusCode.Conflict) {
     logger.info("conflicting backup found");
     const backupEnc = new Uint8Array(await resp.bytes());
     const backupConfig = await provideBackupState(ws);
diff --git a/packages/taler-wallet-core/src/operations/pay.ts 
b/packages/taler-wallet-core/src/operations/pay.ts
index 8fad5599..a42480f4 100644
--- a/packages/taler-wallet-core/src/operations/pay.ts
+++ b/packages/taler-wallet-core/src/operations/pay.ts
@@ -53,6 +53,7 @@ import {
   Logger,
   URL,
   getDurationRemaining,
+  HttpStatusCode,
 } from "@gnu-taler/taler-util";
 import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
 import {
@@ -89,7 +90,6 @@ import {
 } from "../db.js";
 import {
   getHttpResponseErrorDetails,
-  HttpResponseStatus,
   readSuccessResponseJsonOrErrorCode,
   readSuccessResponseJsonOrThrow,
   readTalerErrorResponse,
@@ -1222,7 +1222,7 @@ async function submitPay(
       };
     }
 
-    if (resp.status === HttpResponseStatus.BadRequest) {
+    if (resp.status === HttpStatusCode.BadRequest) {
       const errDetails = await readUnexpectedResponseDetails(resp);
       logger.warn("unexpected 400 response for /pay");
       logger.warn(j2s(errDetails));
@@ -1242,7 +1242,7 @@ async function submitPay(
       throw new OperationFailedAndReportedError(errDetails);
     }
 
-    if (resp.status === HttpResponseStatus.Conflict) {
+    if (resp.status === HttpStatusCode.Conflict) {
       const err = await readTalerErrorResponse(resp);
       if (
         err.code ===
diff --git a/packages/taler-wallet-core/src/operations/refresh.ts 
b/packages/taler-wallet-core/src/operations/refresh.ts
index 144514e1..d727bd06 100644
--- a/packages/taler-wallet-core/src/operations/refresh.ts
+++ b/packages/taler-wallet-core/src/operations/refresh.ts
@@ -14,7 +14,7 @@
  GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
  */
 
-import { encodeCrock, getRandomBytes } from "@gnu-taler/taler-util";
+import { encodeCrock, getRandomBytes, HttpStatusCode } from 
"@gnu-taler/taler-util";
 import {
   CoinRecord,
   CoinSourceType,
@@ -40,7 +40,6 @@ import {
 import { AmountJson, Amounts } from "@gnu-taler/taler-util";
 import { amountToPretty } from "@gnu-taler/taler-util";
 import {
-  HttpResponseStatus,
   readSuccessResponseJsonOrThrow,
   readUnexpectedResponseDetails,
 } from "../util/http.js";
@@ -377,7 +376,7 @@ async function refreshMelt(
     });
   });
 
-  if (resp.status === HttpResponseStatus.NotFound) {
+  if (resp.status === HttpStatusCode.NotFound) {
     const errDetails = await readUnexpectedResponseDetails(resp);
     await ws.db
       .mktx((x) => ({
diff --git a/packages/taler-wallet-core/src/util/http.ts 
b/packages/taler-wallet-core/src/util/http.ts
index d01f2ee4..0556d227 100644
--- a/packages/taler-wallet-core/src/util/http.ts
+++ b/packages/taler-wallet-core/src/util/http.ts
@@ -59,17 +59,6 @@ export interface HttpRequestOptions {
   body?: string | ArrayBuffer | ArrayBufferView;
 }
 
-export enum HttpResponseStatus {
-  Ok = 200,
-  NoContent = 204,
-  Gone = 210,
-  NotModified = 304,
-  BadRequest = 400,
-  PaymentRequired = 402,
-  NotFound = 404,
-  Conflict = 409,
-}
-
 /**
  * Headers, roughly modeled after the fetch API's headers object.
  */

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]