aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.js6
-rw-r--r--src/features/gifts.js2
-rw-r--r--src/features/nostrlogin.js13
-rw-r--r--src/i18n.js1
-rw-r--r--src/pomegranate.js14
-rw-r--r--src/style.css7
6 files changed, 32 insertions, 11 deletions
diff --git a/src/app.js b/src/app.js
index a0be9c8..5f7bbee 100644
--- a/src/app.js
+++ b/src/app.js
@@ -1095,7 +1095,7 @@ function createPane() {
h('div', { class: 'warn-box' }, t('writeDownWarn')),
h(
'div',
- { class: 'words' },
+ { class: 'words', style: '--rows-3:' + Math.ceil(words.length / 3) + ';--rows-2:' + Math.ceil(words.length / 2) },
words.map((w, i) =>
h('div', { class: 'w' }, h('span', { class: 'n' }, i + 1), h('span', { class: 't' }, w))
)
@@ -3053,7 +3053,7 @@ function recoveryCard(a) {
return h('div', { class: 'card col' },
h('h3', {}, t('recoveryPhrase')),
h('div', { class: 'warn-box' }, t('recoveryWarn')),
- h('div', { class: 'words' }, words.map((w, i) =>
+ h('div', { class: 'words', style: '--rows-3:' + Math.ceil(words.length / 3) + ';--rows-2:' + Math.ceil(words.length / 2) }, words.map((w, i) =>
h('div', { class: 'w' + (unmasked ? '' : ' masked') },
h('span', { class: 'n' }, i + 1),
h('span', { class: 't' }, unmasked ? w : '••••••')))),
@@ -3405,7 +3405,7 @@ function onboardScreen() {
title(t('onbBackupTitle')),
h('p', { class: 'muted', style: 'margin:0' }, t('onbBackupBody')),
h('div', { class: 'warn-box' }, t('writeDownWarn')),
- h('div', { class: 'words' }, words.map((w, i) =>
+ h('div', { class: 'words', style: '--rows-3:' + Math.ceil(words.length / 3) + ';--rows-2:' + Math.ceil(words.length / 2) }, words.map((w, i) =>
h('div', { class: 'w' }, h('span', { class: 'n' }, i + 1), h('span', { class: 't' }, w)))),
h('div', { class: 'row gap6' }, copyBtn(acc.mnemonic, t('copyPhrase'))),
h('button', { class: 'btn-primary btn-block', style: 'padding:14px', onClick: done }, t('onbBackupDone')),
diff --git a/src/features/gifts.js b/src/features/gifts.js
index 20b192c..052a107 100644
--- a/src/features/gifts.js
+++ b/src/features/gifts.js
@@ -209,7 +209,7 @@ export function giftsFeature(ctx) {
h('div', { class: 'card col' },
h('h3', {}, t('recoveryPhrase')),
h('div', { class: 'warn-box' }, t('writeDownWarn')),
- h('div', { class: 'words' },
+ h('div', { class: 'words', style: '--rows-3:' + Math.ceil(words.length / 3) + ';--rows-2:' + Math.ceil(words.length / 2) },
words.map((w, i) => h('div', { class: 'w' }, h('span', { class: 'n' }, i + 1), h('span', { class: 't' }, w)))
),
h('div', { class: 'row gap6' }, copyBtn(wallet.mnemonic, t('copyPhrase'))),
diff --git a/src/features/nostrlogin.js b/src/features/nostrlogin.js
index 503384f..1d78b39 100644
--- a/src/features/nostrlogin.js
+++ b/src/features/nostrlogin.js
@@ -311,7 +311,7 @@ export function nostrLoginFeature(ctx) {
// "Sign in with Google" — pomegranate: the code (and its FROST dealer)
// rides in a lazy chunk, so the popup must open HERE, inside the click's
// user activation, and the module navigates it once loaded.
- async function googleLogin(run) {
+ async function googleLogin(run, central = null) {
const popup = window.open('about:blank', 'OAuth', 'width=600,height=600');
ui.nostrLoginError = '';
// no status narration — a quiet spinner on the button itself is the whole
@@ -320,7 +320,7 @@ export function nostrLoginFeature(ctx) {
busy(true);
try {
const pome = await import('../pomegranate.js');
- const { uri } = await pome.loginWithGoogle(popup);
+ const { uri } = await pome.loginWithGoogle(popup, { central });
await run(() => bunkerSigner(uri, { onAuth: (url) => { ui.nostrLoginAuthUrl = url; render(); } }));
} catch (e) {
try { popup && popup.close(); } catch {}
@@ -375,6 +375,12 @@ export function nostrLoginFeature(ctx) {
// Google + passkey, with their transient status rows — shared between the
// collapsed front-door card and the expanded signer list.
+ // Google accounts live per pomegranate central. coinos runs its own
+ // (auth.coinos.io); whoever signed in while auth.njump.me was the default
+ // still has a door to it. Mirrors pomegranate.js's CENTRALS (that module
+ // is a lazy chunk, so the two strings live here too).
+ const GOOGLE_CENTRAL = 'https://auth.njump.me'; // flip to auth.coinos.io with pomegranate.js DEFAULT_CENTRAL
+ const GOOGLE_LEGACY = 'https://auth.njump.me';
function externalButtons(run, big = false) {
const hasPasskey = typeof window !== 'undefined' && !!window.PublicKeyCredential && !!navigator.credentials;
const pad = big ? 'padding:14px' : '';
@@ -382,6 +388,9 @@ export function nostrLoginFeature(ctx) {
h('button', { class: 'btn-block', style: pad, disabled: ui.nostrLoginBusy,
onClick: () => googleLogin(run) },
markedLabel(GOOGLE_MARK, t('nlGoogle'), ui.nostrLoginVia === 'google')),
+ GOOGLE_CENTRAL !== GOOGLE_LEGACY
+ ? h('button', { class: 'linklike small', style: 'align-self:center', disabled: ui.nostrLoginBusy, onClick: () => googleLogin(run, GOOGLE_LEGACY) }, t('nlGooglePrev'))
+ : null,
hasPasskey
? h('button', { class: 'btn-block', style: pad, disabled: ui.nostrLoginBusy,
onClick: () => passkeyLogin(run) }, markedLabel(PASSKEY_MARK, t('nlPasskey'), ui.nostrLoginVia === 'passkey'))
diff --git a/src/i18n.js b/src/i18n.js
index c3fa08b..66ed1a8 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -842,6 +842,7 @@ const STR = {
onbStartHint: "Takes a minute: write down twelve words and it's yours",
onbOrSignIn: 'or',
onbHaveSeed: 'Have an existing seed or entropy to import?',
+ nlGooglePrev: 'Signed in with Google here before? Use the previous sign-in server',
onbCreateInstead: 'Create a new wallet instead',
onbBackupTitle: 'Write down your recovery phrase',
onbBackupBody: "Signing in was the easy part — but the sign-in isn't your wallet. These twelve words are. They're the only way back in if you lose access to that account, and nobody can reissue them for you.",
diff --git a/src/pomegranate.js b/src/pomegranate.js
index 59a1d3b..e86b650 100644
--- a/src/pomegranate.js
+++ b/src/pomegranate.js
@@ -19,7 +19,13 @@ import { hex } from '@scure/base';
import { finalizeEvent, generateSecretKey } from 'nostr-tools/pure';
import { hexPubShard, hexShard, trustedKeyDeal } from '@jsr/fiatjaf__promenade-trusted-dealer';
-export const CENTRAL = 'https://auth.njump.me';
+// Which central: coinos runs its own (auth.coinos.io — the Google consent
+// screen and the bunker relay carry our name), but accounts live PER
+// central, so anyone who signed in while auth.njump.me was the default
+// keeps a door to it (see nostrlogin's "previous server" line).
+export const CENTRALS = { coinos: 'https://auth.coinos.io', legacy: 'https://auth.njump.me' };
+export const DEFAULT_CENTRAL = CENTRALS.legacy; // flip to CENTRALS.coinos once its Google client is live
+let CENTRAL = DEFAULT_CENTRAL;
const OPERATORS = [
'https://po.f7z.io',
'https://po.coracle.social',
@@ -147,8 +153,10 @@ async function bunkerUri(token) {
}
// The whole flow: authenticate, find-or-create the sharded account, hand back
-// a bunker URI. `popup` must come from the caller's click handler.
-export async function loginWithGoogle(popup, { onStatus } = {}) {
+// a bunker URI. `popup` must come from the caller's click handler; `central`
+// picks the server (default: DEFAULT_CENTRAL).
+export async function loginWithGoogle(popup, { onStatus, central } = {}) {
+ CENTRAL = central || DEFAULT_CENTRAL;
const token = await authenticate(popup);
const email = emailOf(token);
if (!email) throw new Error('Google login returned no email');
diff --git a/src/style.css b/src/style.css
index 8cdd92d..36698ae 100644
--- a/src/style.css
+++ b/src/style.css
@@ -254,7 +254,10 @@ textarea { resize: vertical; min-height: 84px; font-family: var(--mono); font-si
.addr-check .hl { color: var(--ink); font-weight: 700; }
/* ---- mnemonic grid ---- */
-.words { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
+/* Words run DOWN a column, then the next — the way a hand copies a list —
+ so on a phone (two columns) the first column is 1–6, not 1,3,5,…; the row
+ count comes from the word count (--rows-3 / --rows-2, set inline). */
+.words { display: grid; grid-auto-flow: column; grid-template-rows: repeat(var(--rows-3, 4), auto); grid-auto-columns: 1fr; gap: 8px; }
.words .w {
display: flex; align-items: baseline; gap: 7px; background: var(--surface2);
border: 1px solid var(--line); border-radius: 10px; padding: 9px 11px; font-family: var(--mono);
@@ -366,7 +369,7 @@ hr.divider { margin: 16px 0; }
/* ---- how it works ---- */
@media (max-width: 420px) {
- .words { grid-template-columns: repeat(2, 1fr); }
+ .words { grid-template-rows: repeat(var(--rows-2, 6), auto); }
.balance .amt { font-size: 28px; }
}