diff --git a/ng-app/src-tauri/src/lib.rs b/ng-app/src-tauri/src/lib.rs index 0056855..b586663 100644 --- a/ng-app/src-tauri/src/lib.rs +++ b/ng-app/src-tauri/src/lib.rs @@ -359,6 +359,15 @@ async fn decode_invitation(invite: String) -> Option { decode_invitation_string(invite) } +#[tauri::command(rename_all = "snake_case")] +async fn retrieve_ng_bootstrap( + location: String, +) -> Result { + ng_net::utils::retrieve_ng_bootstrap(&location) + .await + .ok_or("cannot retrieve bootstrap".to_string()) +} + #[tauri::command(rename_all = "snake_case")] async fn file_get( session_id: u64, @@ -1073,6 +1082,7 @@ impl AppBuilder { signed_snapshot_request, update_header, fetch_header, + retrieve_ng_bootstrap, ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); diff --git a/ng-app/src/App.svelte b/ng-app/src/App.svelte index cf69dd3..3150d4a 100644 --- a/ng-app/src/App.svelte +++ b/ng-app/src/App.svelte @@ -41,6 +41,7 @@ import ng from "./api"; import AccountInfo from "./routes/AccountInfo.svelte"; + import WalletLoginUsername from "./routes/WalletLoginUsername.svelte"; import WalletLoginQr from "./routes/WalletLoginQr.svelte"; import WalletLoginTextCode from "./routes/WalletLoginTextCode.svelte"; @@ -48,6 +49,7 @@ routes.set("/", Home); routes.set("/test", Test); routes.set("/wallet/login", WalletLogin); + routes.set("/wallet/username", WalletLoginUsername); routes.set("/wallet/login-qr", WalletLoginQr); routes.set("/wallet/login-text-code", WalletLoginTextCode); routes.set("/wallet/create", WalletCreate); diff --git a/ng-app/src/api.ts b/ng-app/src/api.ts index b596967..f4fc36e 100644 --- a/ng-app/src/api.ts +++ b/ng-app/src/api.ts @@ -54,7 +54,8 @@ const mapping = { "signed_snapshot_request": ["session_id", "nuri"], "signature_request": ["session_id", "nuri"], "update_header": ["session_id","nuri","title","about"], - "fetch_header": ["session_id", "nuri"] + "fetch_header": ["session_id", "nuri"], + "retrieve_ng_bootstrap": ["location"], } diff --git a/ng-app/src/lib/components/PasswordInput.svelte b/ng-app/src/lib/components/PasswordInput.svelte index c0a5192..1470f57 100644 --- a/ng-app/src/lib/components/PasswordInput.svelte +++ b/ng-app/src/lib/components/PasswordInput.svelte @@ -13,9 +13,10 @@ export let value: string | undefined = undefined; export let placeholder: string | undefined = undefined; export let className: string | undefined = undefined; + export let classNameToggle: string | undefined = "right-0"; export let id: string | undefined = undefined; export let auto_complete: string | undefined = undefined; - + import { createEventDispatcher } from "svelte"; export let show: boolean = false; let input; @@ -28,6 +29,8 @@ value = target.value; } + const dispatch = createEventDispatcher(); + async function toggle() { let { selectionStart, selectionEnd } = input; show = !show; @@ -37,6 +40,11 @@ input.selectionEnd = selectionEnd; }, 0); } + const key_pressed = async (e: any) => { + if (e.key == "Enter" || e.keyCode == 13) { + dispatch("enter"); + } + }
@@ -51,10 +59,11 @@ on:input={handleInput} class={`${className} pr-12 text-md block`} autocomplete={auto_complete} + on:keypress={key_pressed} />
Dein Kreditkarten-PIN ist zum Beispiel eine gute Wahl.
Wir bei NextGraph werden deinen PIN niemals sehen.", + "description": "Wir empfehlen, einen PIN zu wählen, den du bereits sehr gut kennst.
Wir bei NextGraph werden deinen PIN niemals sehen.", "rules": "Hier sind die Regeln für den PIN:", "1": "Er darf keine Zahlenfolge wie 1234 oder 8765 sein.", "2": "Die gleiche Ziffer darf nicht mehr als einmal wiederholt werden. Zum Beispiel ist 4484 ungültig.", @@ -234,18 +235,18 @@ "from_import.title": "Dein Wallet wurde übertragen", "from_import.description": "Dein Wallet wurde empfangen:", "from_import.instruction": "Um den Import abzuschließen, melde dich bitte an.", - "with_another_wallet": "Mit einem anderen Wallet anmelden", - "import_wallet": "Dein Wallet importieren", - "import_file": "Wallet-Datei importieren", - "import_qr": "Mit QR-Code importieren", - "import_link": "Mit TextCode importieren", - "new_wallet": "Ein neues Wallet erstellen", + "with_username": "Mit Benutzername", + "import_file": "Wallet-Datei", + "import_qr": "Mit QR-Code", + "import_link": "Mit TextCode", + "new_wallet": "neues Wallet erstellen", "logged_in": "Du bist angemeldet.
Bitte warte, während die App geladen wird." }, "wallet_login_qr": { "title": "Wallet mit QR-Code importieren", "scan.description": "Um dein Wallet von einem anderen Gerät zu importieren, erzeuge dort einen Export-QR-Code. Gehe zum Erstellen zu
Nutzerbereich > Wallet > Export: QR-Code erstellen.", "scan.modal.title": "Export-QR-Code scannen", + "gen.button": "QR-Code anzeigen", "gen.description": "Um dein Wallet von einem anderen Gerät zu importieren, kannst du hier auf diesem Gerät einen Import-QR-Code generieren und ihn dann mit deinem anderen Gerät scannen. Gehe auf dem anderen Gerät zu
Nutzerbereich > Wallet > Export: QR scannen, um zu exportieren.", "gen.generated": "Scanne diesen QR-Code vom anderen Gerät aus.", "success_btn": "Weiter zur Anmeldung" diff --git a/ng-app/src/locales/en.json b/ng-app/src/locales/en.json index 50f07ea..616dbb8 100644 --- a/ng-app/src/locales/en.json +++ b/ng-app/src/locales/en.json @@ -342,7 +342,7 @@ }, "no_wallet": { "welcome": "Welcome to NextGraph", - "description": "We could not find a wallet saved on this device.
If you already have a wallet, select \"Log in\", otherwise, select \"Create Wallet\" here below.", + "description": "We could not find a wallet saved on this device.
If you already have a wallet, select \"Login\", otherwise, select \"Create Wallet\" here below.", "create_wallet": "Create Wallet" }, "login": { @@ -425,7 +425,8 @@ "choose_broker": "Please choose one broker among the list", "register_with_broker": "Register with {broker}", "for_eu_citizens": "European Union Server", - "for_rest": "For the rest of the world", + "for_rest": "International Server", + "this_broker": "this Broker", "enter_invite_link": "Enter an invitation link", "scan_invite_qr": "Scan an invitation QR-code", "self_hosted_broker": "Self-hosted broker", @@ -434,7 +435,7 @@ "registration_success": "You have been successfully registered to {broker}", "choose_pin": { "title": "Let's start creating your wallet by choosing a PIN code", - "description": "We recommend you to choose a PIN code that you already know very well.
Your credit card PIN, by example, is a good choice.
We at NextGraph will never see your PIN.", + "description": "We recommend you to choose a PIN code that you already know very well.
We at NextGraph will never see your PIN.", "rules": "Here are the rules for the PIN:", "1": "It cannot be a series like 1234 or 8765.", "2": "The same digit cannot repeat more than once. By example 4484 is invalid.", @@ -509,13 +510,35 @@ "from_import.title": "Your wallet has been transferred", "from_import.description": "Your wallet has been received from the other device!", "from_import.instruction": "To finish the import, please log in.", - "with_another_wallet": "Log in with another wallet", - "import_wallet": "Import your wallet", + "with_username": "with my Username", "import_file": "Import a Wallet File", "import_qr": "Import with QR-Code", "import_link": "Import with TextCode", "new_wallet": "Create a new Wallet", - "logged_in": "You are logged in.
please wait while the app is loading" + "logged_in": "You are logged in.
please wait while the app is loading", + "offline_advice": "If you do not have internet on this device, you can use the \"Import a Wallet file\" method instead." + }, + "wallet_login_username": { + "title": "Import Wallet with your Username", + "description": "If you have created a username and password for your Wallet, then you can enter the details here below in order to import your wallet from your broker. You only have to do that once on this device.", + "username": "Username", + "username_placeholder_domain": "with the @domain part", + "username_placeholder_without_domain": "without @{domain}", + "username_placeholder_without_at": "without the @domain part", + "password": "Password", + "password_placeholder": "Enter your password here", + "next": "Next", + "connect": "Connect", + "redirect": "Redirect me", + "retrieve_button": "Connect & Retrieve Wallet", + "success_btn": "Continue to Login", + "error.username": "The username you entered is invalid. Only alphanumerical characters are allowed (together with hyphen and underscore)", + "error.nodomainplease": "Please enter your username without a trailing @domain", + "warning.nodomainplease": "You shouldn't enter any @domain part for your username", + "warning.nospecificdomainplease": "You don't need to enter the @{domain} part of your username", + "error.invalid_domain": "the @domain part is invalid", + "error.mandatory_domain": "You must enter the @domain part of your username.", + "error.need_redirect": "This user is from another broker. Do you want to be redirected to that broker?" }, "wallet_login_qr": { "title": "Import Wallet with QR-Code", @@ -523,7 +546,6 @@ "scan.modal.title": "Scan Wallet QR-Code", "gen.button": "Generate QR-Code", "gen.description": "To import your wallet from another device, you have to generate a QR-Code here on this device, and then scan it with your other device (the one where your wallet is located for now).
If your other device does not have a camera, then you have to use another method for importing your wallet here.", - "offline_advice": "If you do not have internet on this device, you can use the \"Import a Wallet file\" method instead.", "gen.letsgo": "Ready? On your other device, you first have to be logged-in (wallet is opened) and then you go to
User Panel > Wallet > Export by scanning a QR-code.
Then on this present device, click below on the
Generate QR-Code button.", "gen.generated": "Scan this QR-Code from the other device.
You have 5 minutes to do so.", "success_btn": "Continue to Login" diff --git a/ng-app/src/routes/WalletCreate.svelte b/ng-app/src/routes/WalletCreate.svelte index 867f9ee..bb59455 100644 --- a/ng-app/src/routes/WalletCreate.svelte +++ b/ng-app/src/routes/WalletCreate.svelte @@ -999,7 +999,7 @@ /> {$t("pages.wallet_create.register_with_broker", { - values: { broker: pre_invitation.V0.name || "this broker" }, + values: { broker: pre_invitation.V0.name || $t("pages.wallet_create.this_broker") }, })}
diff --git a/ng-app/src/routes/WalletLogin.svelte b/ng-app/src/routes/WalletLogin.svelte index 4efc76c..f6faef0 100644 --- a/ng-app/src/routes/WalletLogin.svelte +++ b/ng-app/src/routes/WalletLogin.svelte @@ -37,7 +37,7 @@ redirect_after_login, redirect_if_wallet_is } from "../store"; - import { CheckBadge, ExclamationTriangle, QrCode } from "svelte-heros-v2"; + import { CheckBadge, ExclamationTriangle, QrCode, Cloud } from "svelte-heros-v2"; let tauri_platform = import.meta.env.TAURI_PLATFORM; @@ -363,15 +363,16 @@
{/each}
- {#if $has_wallets} -

- {$t("pages.wallet_login.with_another_wallet")} -

- {:else} -

- {$t("pages.wallet_login.import_wallet")} -

- {/if} + + +
{:else if error} diff --git a/ng-app/src/routes/WalletLoginTextCode.svelte b/ng-app/src/routes/WalletLoginTextCode.svelte index aef775b..dd7d217 100644 --- a/ng-app/src/routes/WalletLoginTextCode.svelte +++ b/ng-app/src/routes/WalletLoginTextCode.svelte @@ -73,6 +73,9 @@ {@html $t("wallet_sync.offline_warning")} + + {@html $t("pages.wallet_login.offline_advice")} + {/if} diff --git a/ng-app/src/routes/WalletLoginUsername.svelte b/ng-app/src/routes/WalletLoginUsername.svelte new file mode 100644 index 0000000..7dd48ec --- /dev/null +++ b/ng-app/src/routes/WalletLoginUsername.svelte @@ -0,0 +1,319 @@ + + + + + +
+
+ +
+

{$t("pages.wallet_login_username.title")}

+
+ + {#if !connected} + +
+ + {@html $t("wallet_sync.offline_warning")} + + + {@html $t("pages.wallet_login.offline_advice")} + + + +
+ {:else if error} +
+ +

+ {@html $t("errors.error_occurred", { + values: { message: display_error(error) }, + })} +

+ +
+ {:else} + {#if state == "username"} +
+
+
+ {#if syntax_error} + + {syntax_error} + + {/if} + {#if warning} + + {warning} + + {/if} + {$t("pages.wallet_login_username.username")} : + {syntax_error="";redirect=undefined;}} + /> + + + {#if redirect} + + {:else} + + {/if} +
+
+
+ {:else if state === "password"} +
+
+
+ {$t("pages.wallet_login_username.password")} : + + + + + +
+
+
+ {:else if state === "connecting"} +
+ +
+ {/if} + {/if} +
+
+
diff --git a/ng-net/Cargo.toml b/ng-net/Cargo.toml index 00ba84d..5f47905 100644 --- a/ng-net/Cargo.toml +++ b/ng-net/Cargo.toml @@ -37,8 +37,6 @@ regex = "1.8.4" base64-url = "2.0.0" web-time = "0.2.0" ng-repo = { path = "../ng-repo", version = "0.1.1-alpha" } - -[target.'cfg(target_arch = "wasm32")'.dependencies] reqwest = { version = "0.11.18", features = ["json","native-tls-vendored"] } [target.'cfg(target_arch = "wasm32")'.dependencies.getrandom] diff --git a/ng-net/src/types.rs b/ng-net/src/types.rs index 8bf3a45..b6e7db1 100644 --- a/ng-net/src/types.rs +++ b/ng-net/src/types.rs @@ -503,6 +503,14 @@ impl BrokerServerV0 { } } + pub fn get_domain(&self) -> Option { + if let BrokerServerTypeV0::Domain(domain) = &self.server_type { + Some(domain.clone()) + } else { + None + } + } + /// on web browser, returns the connection URL and an optional list of BindAddress if a relay is needed /// filtered by the current location url of the webpage /// on native apps (do not pass a location), returns or the connection URL without optional BindAddress or an empty string with @@ -825,6 +833,15 @@ impl Invitation { Invitation::V0(v0) => &v0.bootstrap.servers, } } + pub fn get_domain(&self) -> Option { + for bootstrap in self.get_servers() { + let res = bootstrap.get_domain(); + if res.is_some() { + return res; + } + } + None + } pub fn set_name(&mut self, name: Option) { if name.is_some() { diff --git a/ng-net/src/utils.rs b/ng-net/src/utils.rs index 5db1e90..fa8ec15 100644 --- a/ng-net/src/utils.rs +++ b/ng-net/src/utils.rs @@ -28,7 +28,6 @@ use ng_repo::types::PubKey; use ng_repo::{log::*, types::PrivKey}; use crate::types::*; -#[cfg(target_arch = "wasm32")] use crate::NG_BOOTSTRAP_LOCAL_PATH; use crate::WS_PORT; @@ -243,6 +242,42 @@ async fn retrieve_ng_bootstrap(location: &String) -> Option } } +#[cfg(not(target_arch = "wasm32"))] +pub async fn retrieve_ng_bootstrap(location: &String) -> Option { + let url = Url::parse(location).unwrap(); + let prefix = url.origin().unicode_serialization(); + let url = format!("{}{}", prefix, NG_BOOTSTRAP_LOCAL_PATH); + log_info!("url {}", url); + let resp = reqwest::get(url).await; + //log_info!("{:?}", resp); + if resp.is_ok() { + let resp = resp.unwrap().json::().await; + return if resp.is_ok() { + Some(resp.unwrap()) + } else { + None + }; + } else { + //log_info!("err {}", resp.unwrap_err()); + return None; + } +} + +// #[cfg(target_arch = "wasm32")] +// pub async fn retrieve_domain(location: String) -> Option { +// let info = retrieve_ng_bootstrap(&location).await; +// if info.is_none() { +// return None; +// } +// for bootstrap in info.unwrap().servers() { +// let res = bootstrap.get_domain(); +// if res.is_some() { +// return res; +// } +// } +// None +// } + #[cfg(target_arch = "wasm32")] pub async fn retrieve_local_url(location: String) -> Option { let info = retrieve_ng_bootstrap(&location).await; diff --git a/ng-sdk-js/src/lib.rs b/ng-sdk-js/src/lib.rs index 304e8df..5617539 100644 --- a/ng-sdk-js/src/lib.rs +++ b/ng-sdk-js/src/lib.rs @@ -77,6 +77,17 @@ pub async fn get_local_bootstrap(location: String, invite: JsValue) -> JsValue { } } +#[wasm_bindgen] +pub async fn get_local_bootstrap_and_domain(location: String) -> JsValue { + let res = retrieve_local_bootstrap(location, None, false).await; + if res.is_some() { + let domain = res.as_ref().unwrap().get_domain(); + serde_wasm_bindgen::to_value(&(res.unwrap(), domain)).unwrap() + } else { + serde_wasm_bindgen::to_value(&(false, false)).unwrap() + } +} + #[wasm_bindgen] pub async fn get_local_bootstrap_with_public( location: String,