gnunet-svn
[Top][All Lists]
Advanced

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

[taler-wallet-core] branch master updated: add provider/ remove provider


From: gnunet
Subject: [taler-wallet-core] branch master updated: add provider/ remove provider
Date: Tue, 09 Nov 2021 04:20:01 +0100

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

sebasjm pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 7f6101a2 add provider/ remove provider
7f6101a2 is described below

commit 7f6101a24df0db86f33c3217e52838f09a25286d
Author: Sebastian <sebasjm@gmail.com>
AuthorDate: Tue Nov 9 00:19:50 2021 -0300

    add provider/ remove provider
---
 packages/anastasis-core/src/index.ts               | 66 +++++++++++++++
 packages/anastasis-core/src/reducer-types.ts       |  8 ++
 .../pages/home/AddingProviderScreen.stories.tsx    |  6 ++
 .../src/pages/home/AddingProviderScreen.tsx        | 99 +++++++++++++---------
 .../src/pages/home/AuthenticationEditorScreen.tsx  | 26 ++++--
 .../src/pages/home/SecretSelectionScreen.tsx       | 12 +++
 .../src/pages/home/authMethod/index.tsx            |  8 +-
 7 files changed, 175 insertions(+), 50 deletions(-)

diff --git a/packages/anastasis-core/src/index.ts 
b/packages/anastasis-core/src/index.ts
index f88e6e8b..15e1e5d9 100644
--- a/packages/anastasis-core/src/index.ts
+++ b/packages/anastasis-core/src/index.ts
@@ -65,6 +65,8 @@ import {
   ActionArgsChangeVersion,
   TruthMetaData,
   ActionArgsUpdatePolicy,
+  ActionArgsAddProvider,
+  ActionArgsDeleteProvider,
 } from "./reducer-types.js";
 import fetchPonyfill from "fetch-ponyfill";
 import {
@@ -1060,9 +1062,15 @@ async function recoveryEnterUserAttributes(
   args: ActionArgsEnterUserAttributes,
 ): Promise<ReducerStateRecovery | ReducerStateError> {
   // FIXME: validate attributes
+  const providerUrls = Object.keys(state.authentication_providers ?? {});
+  const newProviders = state.authentication_providers ?? {};
+  for (const url of providerUrls) {
+    newProviders[url] = await getProviderInfo(url);
+  }
   const st: ReducerStateRecovery = {
     ...state,
     identity_attributes: args.identity_attributes,
+    authentication_providers: newProviders,
   };
   return downloadPolicy(st);
 }
@@ -1174,6 +1182,60 @@ function transitionRecoveryJump(
   };
 }
 
+//FIXME: doest the same that addProviderRecovery, but type are not generic 
enough
+async function addProviderBackup(
+  state: ReducerStateBackup,
+  args: ActionArgsAddProvider,
+): Promise<ReducerStateBackup> {
+  const info = await getProviderInfo(args.provider_url)
+  return {
+    ...state,
+    authentication_providers: {
+      ...(state.authentication_providers ?? {}),
+      [args.provider_url]: info,
+    },
+  };
+}
+
+//FIXME: doest the same that deleteProviderRecovery, but type are not generic 
enough
+async function deleteProviderBackup(
+  state: ReducerStateBackup,
+  args: ActionArgsDeleteProvider,
+): Promise<ReducerStateBackup> {
+  const authentication_providers = {... state.authentication_providers ?? {} }
+  delete authentication_providers[args.provider_url]
+  return {
+    ...state,
+    authentication_providers,
+  };
+}
+
+async function addProviderRecovery(
+  state: ReducerStateRecovery,
+  args: ActionArgsAddProvider,
+): Promise<ReducerStateRecovery> {
+  const info = await getProviderInfo(args.provider_url)
+  return {
+    ...state,
+    authentication_providers: {
+      ...(state.authentication_providers ?? {}),
+      [args.provider_url]: info,
+    },
+  };
+}
+
+async function deleteProviderRecovery(
+  state: ReducerStateRecovery,
+  args: ActionArgsDeleteProvider,
+): Promise<ReducerStateRecovery> {
+  const authentication_providers = {... state.authentication_providers ?? {} }
+  delete authentication_providers[args.provider_url]
+  return {
+    ...state,
+    authentication_providers,
+  };
+}
+
 async function addAuthentication(
   state: ReducerStateBackup,
   args: ActionArgsAddAuthentication,
@@ -1408,6 +1470,8 @@ const backupTransitions: Record<
     ...transitionBackupJump("back", BackupStates.UserAttributesCollecting),
     ...transition("add_authentication", codecForAny(), addAuthentication),
     ...transition("delete_authentication", codecForAny(), 
deleteAuthentication),
+    ...transition("add_provider", codecForAny(), addProviderBackup),
+    ...transition("delete_provider", codecForAny(), deleteProviderBackup),
     ...transition("next", codecForAny(), nextFromAuthenticationsEditing),
   },
   [BackupStates.PoliciesReviewing]: {
@@ -1476,6 +1540,8 @@ const recoveryTransitions: Record<
   [RecoveryStates.SecretSelecting]: {
     ...transitionRecoveryJump("back", RecoveryStates.UserAttributesCollecting),
     ...transitionRecoveryJump("next", RecoveryStates.ChallengeSelecting),
+    ...transition("add_provider", codecForAny(), addProviderRecovery),
+    ...transition("delete_provider", codecForAny(), deleteProviderRecovery),
     ...transition(
       "change_version",
       codecForActionArgsChangeVersion(),
diff --git a/packages/anastasis-core/src/reducer-types.ts 
b/packages/anastasis-core/src/reducer-types.ts
index 51b0045a..3e6d6c85 100644
--- a/packages/anastasis-core/src/reducer-types.ts
+++ b/packages/anastasis-core/src/reducer-types.ts
@@ -334,6 +334,14 @@ export const codecForActionArgsEnterUserAttributes = () =>
     .property("identity_attributes", codecForAny())
     .build("ActionArgsEnterUserAttributes");
 
+export interface ActionArgsAddProvider {
+  provider_url: string;
+}
+
+export interface ActionArgsDeleteProvider {
+  provider_url: string;
+}
+
 export interface ActionArgsAddAuthentication {
   authentication_method: {
     type: string;
diff --git 
a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx 
b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx
index a96734ca..08e2b437 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.stories.tsx
@@ -40,6 +40,12 @@ export const NewProvider = createExample(TestedComponent, {
   ...reducerStatesExample.authEditing,
 } as ReducerState);
 
+
+export const NewProviderWithoutProviderList = createExample(TestedComponent, {
+  ...reducerStatesExample.authEditing,
+  authentication_providers: {}
+} as ReducerState);
+
 export const NewVideoProvider = createExample(TestedComponent, {
   ...reducerStatesExample.authEditing,
 } as ReducerState, { providerType: 'video'});
diff --git a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx 
b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
index 5cf6fbb0..7504f4d2 100644
--- a/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AddingProviderScreen.tsx
@@ -1,6 +1,6 @@
 import { AuthenticationProviderStatusOk } from "anastasis-core";
 import { h, VNode } from "preact";
-import { useEffect, useLayoutEffect, useRef, useState } from "preact/hooks";
+import { useEffect, useRef, useState } from "preact/hooks";
 import { TextInput } from "../../components/fields/TextInput";
 import { useAnastasisContext } from "../../context/anastasis";
 import { authMethods, KnownAuthMethods } from "./authMethod";
@@ -8,13 +8,13 @@ import { AnastasisClientFrame } from "./index";
 
 interface Props {
   providerType?: KnownAuthMethods;
-  cancel: () => void;
+  onCancel: () => void;
 }
 
 
 async function testProvider(url: string, expectedMethodType?: string): 
Promise<void> {
   try {
-    const response = await fetch(`${url}/config`)
+    const response = await fetch(new URL("config", url).href)
     const json = await (response.json().catch(d => ({})))
     if (!("methods" in json) || !Array.isArray(json.methods)) {
       throw Error("This provider doesn't have authentication method. Check the 
provider URL")
@@ -41,7 +41,7 @@ async function testProvider(url: string, expectedMethodType?: 
string): Promise<v
 
 }
 
-export function AddingProviderScreen({ providerType, cancel }: Props): VNode {
+export function AddingProviderScreen({ providerType, onCancel }: Props): VNode 
{
   const reducer = useAnastasisContext();
 
   const [providerURL, setProviderURL] = useState("");
@@ -54,8 +54,8 @@ export function AddingProviderScreen({ providerType, cancel 
}: Props): VNode {
   useEffect(() => {
     if (timeout) window.clearTimeout(timeout.current)
     timeout.current = window.setTimeout(async () => {
-      const url = providerURL.endsWith('/') ? providerURL.substring(0, 
providerURL.length - 1) : providerURL
-      if (!url) return;
+      const url = providerURL.endsWith('/') ? providerURL : (providerURL + '/')
+      if (!providerURL || authProviders.includes(url)) return;
       try {
         setTesting(true)
         await testProvider(url, providerType)
@@ -67,40 +67,50 @@ export function AddingProviderScreen({ providerType, cancel 
}: Props): VNode {
         if (e instanceof Error) setError(e.message)
       }
       setTesting(false)
-    }, 1000);
-  }, [providerURL])
+    }, 200);
+  }, [providerURL, reducer])
 
 
   if (!reducer) {
     return <div>no reducer in context</div>;
   }
 
-  function addProvider(): void {
-    // addAuthMethod({
-    //   authentication_method: {
-    //     type: "sms",
-    //     instructions: `SMS to ${providerURL}`,
-    //     challenge: encodeCrock(stringToBytes(providerURL)),
-    //   },
-    // });
+  if (!reducer.currentReducerState || !("authentication_providers" in 
reducer.currentReducerState)) {
+    return <div>invalid state</div>
+  }
+
+  async function addProvider(provider_url: string): Promise<void> {
+    await reducer?.transition("add_provider", { provider_url })
+    onCancel()
+  }
+  function deleteProvider(provider_url: string): void {
+    reducer?.transition("delete_provider", { provider_url })
   }
 
+  const allAuthProviders = 
reducer.currentReducerState.authentication_providers || {}
+  const authProviders = Object.keys(allAuthProviders).filter(provUrl => {
+    const p = allAuthProviders[provUrl];
+    if (!providerLabel) {
+      return p && ("currency" in p)
+    } else {
+      return p && ("currency" in p) && p.methods.findIndex(m => m.type === 
providerType) !== -1
+    }
+  })
+
   let errors = !providerURL ? 'Add provider URL' : undefined
+  let url: string | undefined;
   try {
-    new URL(providerURL)
+    url = new URL("",providerURL).href
   } catch {
     errors = 'Check the URL'
   }
   if (!!error && !errors) {
     errors = error
   }
-
-  if (!reducer.currentReducerState || !("authentication_providers" in 
reducer.currentReducerState)) {
-    return <div>invalid state</div>
+  if (!errors && authProviders.includes(url!)) {
+    errors = 'That provider is already known'
   }
 
-  const authProviders = reducer.currentReducerState.authentication_providers 
|| {}
-
   return (
     <AnastasisClientFrame hideNav
       title="Backup: Manage providers"
@@ -119,40 +129,45 @@ export function AddingProviderScreen({ providerType, 
cancel }: Props): VNode {
             label="Provider URL"
             placeholder="https://provider.com";
             grabFocus
+            error={errors}
             bind={[providerURL, setProviderURL]} />
         </div>
         <p class="block">
           Example: https://kudos.demo.anastasis.lu
         </p>
-
-        {testing && <p class="block has-text-info">Testing</p>}
-        {!!error && <p class="block has-text-danger">{error}</p>}
-        {error === "" && <p class="block has-text-success">This provider 
worked!</p>}
-
+        {testing && <p class="has-text-info">Testing</p>}
+        
         <div class="block" style={{ marginTop: '2em', display: 'flex', 
justifyContent: 'space-between' }}>
-          <button class="button" onClick={cancel}>Cancel</button>
+          <button class="button" onClick={onCancel}>Cancel</button>
           <span data-tooltip={errors}>
-            <button class="button is-info" disabled={error !== "" || testing} 
onClick={addProvider}>Add</button>
+            <button class="button is-info" disabled={error !== "" || testing} 
onClick={() => addProvider(url!)}>Add</button>
           </span>
         </div>
 
-        <p class="subtitle">
-          Current providers
-        </p>
-        {/* <table class="table"> */}
-        {Object.keys(authProviders).map(k => {
-          const p = authProviders[k]
-          if (("currency" in p)) {
-            return <TableRow url={k} info={p} />
-          }
-        }
+        {authProviders.length > 0 ? (
+          !providerLabel ?
+            <p class="subtitle">
+              Current providers
+            </p> : <p class="subtitle">
+              Current providers for {providerLabel} service
+            </p>
+        ) : (
+          !providerLabel ? <p class="subtitle">
+            No known providers, add one.
+          </p> : <p class="subtitle">
+            No known providers for {providerLabel} service
+          </p>
         )}
-        {/* </table> */}
+
+        {authProviders.map(k => {
+          const p = allAuthProviders[k] as AuthenticationProviderStatusOk
+          return <TableRow url={k} info={p} onDelete={deleteProvider} />
+        })}
       </div>
     </AnastasisClientFrame>
   );
 }
-function TableRow({ url, info }: { url: string, info: 
AuthenticationProviderStatusOk }) {
+function TableRow({ url, info, onDelete }: { onDelete: (s: string) => void, 
url: string, info: AuthenticationProviderStatusOk }) {
   const [status, setStatus] = useState("checking")
   useEffect(function () {
     testProvider(url.endsWith('/') ? url.substring(0, url.length - 1) : url)
@@ -174,7 +189,7 @@ function TableRow({ url, info }: { url: string, info: 
AuthenticationProviderStat
       </dl>
     </div>
     <div class="block" style={{ marginTop: 'auto', marginBottom: 'auto', 
display: 'flex', justifyContent: 'space-between', flexDirection: 'column' }}>
-      <button class="button is-danger" >Remove</button>
+      <button class="button is-danger" onClick={() => 
onDelete(url)}>Remove</button>
     </div>
   </div>
 }
\ No newline at end of file
diff --git 
a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx 
b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
index 0bc735f3..00eb54d4 100644
--- a/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/AuthenticationEditorScreen.tsx
@@ -2,10 +2,12 @@ import { AuthMethod, ReducerStateBackup } from 
"anastasis-core";
 import { ComponentChildren, Fragment, h, VNode } from "preact";
 import { useState } from "preact/hooks";
 import { useAnastasisContext } from "../../context/anastasis";
+import { AddingProviderScreen } from "./AddingProviderScreen";
 import {
   authMethods,
   AuthMethodSetupProps,
   AuthMethodWithRemove,
+  isKnownAuthMethods,
   KnownAuthMethods,
 } from "./authMethod";
 import { AnastasisClientFrame } from "./index";
@@ -18,6 +20,8 @@ export function AuthenticationEditorScreen(): VNode {
     KnownAuthMethods | undefined
   >(undefined);
   const [tooFewAuths, setTooFewAuths] = useState(false);
+  const [manageProvider, setManageProvider] = useState<string | 
undefined>(undefined)
+
   // const [addingProvider, setAddingProvider] = useState<string | 
undefined>(undefined)
   const reducer = useAnastasisContext();
   if (!reducer) {
@@ -63,6 +67,14 @@ export function AuthenticationEditorScreen(): VNode {
     }
   }
 
+  if (manageProvider !== undefined) {
+    
+    return <AddingProviderScreen
+      onCancel={() => setManageProvider(undefined)}
+      providerType={isKnownAuthMethods(manageProvider) ? manageProvider : 
undefined}
+    />
+  }
+
   if (selectedMethod) {
     const cancel = (): void => setSelectedMethod(undefined);
     const addMethod = (args: any): void => {
@@ -86,9 +98,9 @@ export function AuthenticationEditorScreen(): VNode {
             active
             onCancel={cancel}
             description="No providers founds"
-            label="Add a provider manually (not implemented!)"
+            label="Add a provider manually"
             onConfirm={() => {
-              null;
+              setManageProvider(selectedMethod)
             }}
           >
             <p>
@@ -179,9 +191,9 @@ export function AuthenticationEditorScreen(): VNode {
               active={!noProvidersAck}
               onCancel={() => setNoProvidersAck(true)}
               description="No providers founds"
-              label="Add a provider manually (not implemented!)"
+              label="Add a provider manually"
               onConfirm={() => {
-                null;
+                setManageProvider("")
               }}
             >
               <p>
@@ -201,11 +213,11 @@ export function AuthenticationEditorScreen(): VNode {
             identity via the methods you configure here. The list of
             authentication method is defined by the backup provider list.
           </p>
-          {/* <p class="block">
-            <button class="button is-info">
+          <p class="block">
+            <button class="button is-info" onClick={() => 
setManageProvider("")}>
               Manage backup providers
             </button>
-          </p> */}
+          </p>
           {authAvailableSet.size > 0 && (
             <p class="block">
               We couldn't find provider for some of the authentication methods.
diff --git a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx 
b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
index cf38d3f1..b1ec2856 100644
--- a/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
+++ b/packages/anastasis-webui/src/pages/home/SecretSelectionScreen.tsx
@@ -3,12 +3,14 @@ import { useState } from "preact/hooks";
 import { AsyncButton } from "../../components/AsyncButton";
 import { NumberInput } from "../../components/fields/NumberInput";
 import { useAnastasisContext } from "../../context/anastasis";
+import { AddingProviderScreen } from "./AddingProviderScreen";
 import { AnastasisClientFrame } from "./index";
 
 export function SecretSelectionScreen(): VNode {
   const [selectingVersion, setSelectingVersion] = useState<boolean>(false);
   const reducer = useAnastasisContext()
 
+  const [manageProvider, setManageProvider] = useState(false)
   const currentVersion = (reducer?.currentReducerState
     && ("recovery_document" in reducer.currentReducerState)
     && reducer.currentReducerState.recovery_document?.version) || 0;
@@ -49,6 +51,10 @@ export function SecretSelectionScreen(): VNode {
     />
   }
 
+  if (manageProvider) {
+    return <AddingProviderScreen onCancel={() => setManageProvider(false)} />
+  }
+
   return (
     <AnastasisClientFrame title="Recovery: Select secret">
       <div class="columns">
@@ -69,6 +75,12 @@ export function SecretSelectionScreen(): VNode {
         </div>
         <div class="column">
           <p>Secret found, you can select another version or continue to the 
challenges solving</p>
+          <p class="block">
+            <button class="button is-info" onClick={() => 
setManageProvider(true)}>
+              Manage recovery providers
+            </button>
+          </p>
+
         </div>
       </div>
     </AnastasisClientFrame>
diff --git a/packages/anastasis-webui/src/pages/home/authMethod/index.tsx 
b/packages/anastasis-webui/src/pages/home/authMethod/index.tsx
index 07f6ec20..8b0126ce 100644
--- a/packages/anastasis-webui/src/pages/home/authMethod/index.tsx
+++ b/packages/anastasis-webui/src/pages/home/authMethod/index.tsx
@@ -41,7 +41,13 @@ interface AuthMethodConfiguration {
   solve: (props: AuthMethodSolveProps) => VNode;
   skip?: boolean;
 }
-export type KnownAuthMethods = "sms" | "email" | "post" | "question" | "video" 
| "totp" | "iban";
+// export type KnownAuthMethods = "sms" | "email" | "post" | "question" | 
"video" | "totp" | "iban";
+
+const ALL_METHODS = ['sms', 'email', 'post', 'question', 'video' , 'totp', 
'iban'] as const;
+export type KnownAuthMethods = (typeof ALL_METHODS)[number];
+export function isKnownAuthMethods(value: string): value is KnownAuthMethods {
+  return ALL_METHODS.includes(value as KnownAuthMethods)
+}
 
 type KnowMethodConfig = {
   [name in KnownAuthMethods]: AuthMethodConfiguration;

-- 
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]