From af2dbb336d29105e617c81d8ba85611917cc966f Mon Sep 17 00:00:00 2001 From: Blockyheadman <80011716+Blockyheadman@users.noreply.github.com> Date: Thu, 13 Aug 2026 11:44:42 -0500 Subject: [PATCH 1/4] fix leftover bug --- src/apps/core/newloginapp/runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/core/newloginapp/runtime.ts b/src/apps/core/newloginapp/runtime.ts index 1ba59437c..0ea3bcee6 100644 --- a/src/apps/core/newloginapp/runtime.ts +++ b/src/apps/core/newloginapp/runtime.ts @@ -132,7 +132,7 @@ export class NewLoginAppRuntime extends AppProcess implements INewLoginAppRuntim this.Persistence.update((v) => { const userConnector = Server.GetConn("UserConnector", ""); const persistence: LoginPersistenceUser = { - displayName: info.preferences.account.displayName ?? info.username, + displayName: info.username, username: info.username, userId: info._id, profilePictureUrl: userConnector.PictureUrl(info._id), From a5d89a54cc6bcd6e20ba7c5b562de2634260fbda Mon Sep 17 00:00:00 2001 From: Blockyheadman <80011716+Blockyheadman@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:58:38 -0500 Subject: [PATCH 2/4] =?UTF-8?q?add=20totp=20shtuff=20=F0=9F=A4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../firstrun/FirstRun/Page/TOTPFailed.svelte | 9 +++ .../firstrun/FirstRun/Page/TOTPSetup.svelte | 7 ++ src/apps/components/firstrun/store.ts | 75 ++++++++++++++++++- .../totpsetupgui/TotpSetupGui.svelte | 24 +++++- src/apps/components/totpsetupgui/runtime.ts | 13 +++- src/apps/components/totpsetupgui/store.ts | 1 + .../runtimes/ITotpSetupGuiRuntime.ts | 3 + 7 files changed, 127 insertions(+), 5 deletions(-) create mode 100755 src/apps/components/firstrun/FirstRun/Page/TOTPFailed.svelte create mode 100755 src/apps/components/firstrun/FirstRun/Page/TOTPSetup.svelte create mode 100644 src/apps/components/totpsetupgui/store.ts diff --git a/src/apps/components/firstrun/FirstRun/Page/TOTPFailed.svelte b/src/apps/components/firstrun/FirstRun/Page/TOTPFailed.svelte new file mode 100755 index 000000000..8d2c1ff0a --- /dev/null +++ b/src/apps/components/firstrun/FirstRun/Page/TOTPFailed.svelte @@ -0,0 +1,9 @@ + + + +

2FA Setup Failed

+

Something went wrong when trying to spawn the 2FA setup overlay.

+
+

You can always try again later in the settings app under 'Your ArcOS Identity'.

diff --git a/src/apps/components/firstrun/FirstRun/Page/TOTPSetup.svelte b/src/apps/components/firstrun/FirstRun/Page/TOTPSetup.svelte new file mode 100755 index 000000000..1590f2f70 --- /dev/null +++ b/src/apps/components/firstrun/FirstRun/Page/TOTPSetup.svelte @@ -0,0 +1,7 @@ + + + +

Set-up 2FA?

+

Do you want to secure your ArcOS account by setting up 2FA using your authenticator app?

diff --git a/src/apps/components/firstrun/store.ts b/src/apps/components/firstrun/store.ts index 675ee6de6..56c2bcba6 100755 --- a/src/apps/components/firstrun/store.ts +++ b/src/apps/components/firstrun/store.ts @@ -1,12 +1,18 @@ -import { Daemon } from "$ts/env"; +import type { ITotpConnector } from "$interfaces/modules/server/ITotpConnector"; +import { Daemon, SoundBus } from "$ts/env"; import { UserPaths } from "$ts/user/store"; +import { MessageBox } from "$ts/util/dialog"; import { join } from "$ts/util/fs"; +import { ElevationLevel } from "$types/system/elevation"; import type { ArcShortcut } from "$types/system/shortcut"; +import type { TotpSetupGuiRuntime } from "../totpsetupgui/runtime"; import DisplayName from "./FirstRun/Page/DisplayName.svelte"; import Finish from "./FirstRun/Page/Finish.svelte"; import ProfilePicture from "./FirstRun/Page/ProfilePicture.svelte"; import Style from "./FirstRun/Page/Style.svelte"; import ThirdParty from "./FirstRun/Page/ThirdParty.svelte"; +import TOTPFailed from "./FirstRun/Page/TOTPFailed.svelte"; +import TOTPSetup from "./FirstRun/Page/TOTPSetup.svelte"; import Welcome from "./FirstRun/Page/Welcome.svelte"; import { DarkModeGraphic, LightModeGraphic } from "./images"; import type { FirstRunPage, FirstRunTheme } from "./types"; @@ -127,7 +133,7 @@ export const FirstRunPages = new Map([ right: [ { caption: "Not now", - action: (process) => process.switchPage("finish"), + action: (process) => process.switchPage("totpSetup"), }, { caption: "Enable", @@ -136,7 +142,46 @@ export const FirstRunPages = new Map([ v.security.enableThirdParty = true; return v; }); - process.switchPage("finish"); + process.switchPage("totpSetup"); + }, + suggested: true, + }, + ], + }, + }, + ], + [ + "totpSetup", + { + name: "Set-up 2FA?", + hero: true, + component: TOTPSetup, + actions: { + left: [ + { + caption: "Go back", + action: (process) => process.switchPage("thirdParty"), + }, + ], + right: [ + { + caption: "Skip", + action: (process) => process.switchPage("finish"), + }, + { + caption: "Set-up 2FA", + action: async (process) => { + const totpSetupProc = await process.spawnOverlayApp("TotpSetupGui", process.pid, true); + if (!totpSetupProc) { + process.switchPage("totpFailed"); + SoundBus.playSound("arcos.dialog.error"); + } + + totpSetupProc?.setupState.subscribe((v) => { + if (v === "successful") { + process.switchPage("finish"); + } + }); }, suggested: true, }, @@ -144,6 +189,30 @@ export const FirstRunPages = new Map([ }, }, ], + [ + "totpFailed", + { + name: "2FA Setup Failed", + hero: true, + component: TOTPFailed, + actions: { + left: [ + { + caption: "Go back", + action: (process) => process.switchPage("thirdParty"), + }, + ], + right: [ + { + caption: "Try again", + action: (process) => process.switchPage("totpSetup"), + }, + + { caption: "Finish later", action: (process) => process.switchPage("finish"), suggested: true }, + ], + }, + }, + ], [ "finish", { diff --git a/src/apps/components/totpsetupgui/TotpSetupGui.svelte b/src/apps/components/totpsetupgui/TotpSetupGui.svelte index a3b2b9992..4a428ac55 100755 --- a/src/apps/components/totpsetupgui/TotpSetupGui.svelte +++ b/src/apps/components/totpsetupgui/TotpSetupGui.svelte @@ -7,7 +7,7 @@ import Input from "./TotpSetupGui/Input.svelte"; const { process }: { process: ITotpSetupGuiRuntime } = $props(); - const { code, url } = process; + const { code, url, setupState, firstTimeSetup } = process; let errored = $state(false); let locked = $state(false); @@ -51,6 +51,28 @@ ); $code = ""; } else { + if (firstTimeSetup) { + await MessageBox( + { + title: "ArcOS Security", + message: "Two-factor authentication has now been enabled on your account.", + buttons: [ + { + caption: "Okay", + action: () => { + setupState.set("successful"); + }, + }, + ], + sound: "arcos.dialog.info", + image: "GoodStatusIcon", + }, + process.parentPid, + true + ); + return; + } + MessageBox( { title: "ArcOS Security", diff --git a/src/apps/components/totpsetupgui/runtime.ts b/src/apps/components/totpsetupgui/runtime.ts index 9a10dcb72..d5076478e 100755 --- a/src/apps/components/totpsetupgui/runtime.ts +++ b/src/apps/components/totpsetupgui/runtime.ts @@ -4,16 +4,21 @@ import { AppProcess } from "$ts/apps/process"; import { Daemon } from "$ts/env"; import { Store } from "$ts/writable"; import type { AppProcessData } from "$types/apps/app"; +import type { SetupState } from "./store"; export class TotpSetupGuiRuntime extends AppProcess implements ITotpSetupGuiRuntime { public code = Store(""); public url = Store(""); + public setupState = Store("unfinished"); + public firstTimeSetup: boolean; //#region LIFECYCLE - constructor(pid: number, parentPid: number, app: AppProcessData) { + constructor(pid: number, parentPid: number, app: AppProcessData, firstTimeSetup: boolean = false) { super(pid, parentPid, app); + this.firstTimeSetup = firstTimeSetup; + this.setSource(__SOURCE__); } @@ -27,6 +32,12 @@ export class TotpSetupGuiRuntime extends AppProcess implements ITotpSetupGuiRunt this.url.set(result.result!.url); } + async onClose(): Promise { + if (this.setupState() === "unfinished") this.setupState.set("canceled"); + + return true; + } + //#endregion //#region ACCESS diff --git a/src/apps/components/totpsetupgui/store.ts b/src/apps/components/totpsetupgui/store.ts new file mode 100644 index 000000000..a81af96ad --- /dev/null +++ b/src/apps/components/totpsetupgui/store.ts @@ -0,0 +1 @@ +export type SetupState = "unfinished" | "canceled" | "successful"; diff --git a/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts b/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts index 0efafa313..fd44175c9 100644 --- a/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts +++ b/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts @@ -1,3 +1,4 @@ +import type { SetupState } from "$apps/components/totpsetupgui/store"; import type { IAppProcess } from "$interfaces/IAppProcess"; import type { ReadableStore } from "$types/shared/writable"; @@ -5,6 +6,8 @@ import type { ReadableStore } from "$types/shared/writable"; export interface ITotpSetupGuiRuntime extends IAppProcess { code: ReadableStore; url: ReadableStore; + setupState: ReadableStore; + firstTimeSetup: boolean; validate(): boolean; activateTotp(): Promise; From 5383d3fa408f5db14267fc22bb6445a31d76b08b Mon Sep 17 00:00:00 2001 From: Blockyheadman <80011716+Blockyheadman@users.noreply.github.com> Date: Thu, 13 Aug 2026 15:05:33 -0500 Subject: [PATCH 3/4] change filename to types... stupid blown reference.. --- src/apps/components/totpsetupgui/runtime.ts | 2 +- src/apps/components/totpsetupgui/{store.ts => types.ts} | 0 src/interfaces/runtimes/ITotpSetupGuiRuntime.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/apps/components/totpsetupgui/{store.ts => types.ts} (100%) diff --git a/src/apps/components/totpsetupgui/runtime.ts b/src/apps/components/totpsetupgui/runtime.ts index d5076478e..2fec658de 100755 --- a/src/apps/components/totpsetupgui/runtime.ts +++ b/src/apps/components/totpsetupgui/runtime.ts @@ -4,7 +4,7 @@ import { AppProcess } from "$ts/apps/process"; import { Daemon } from "$ts/env"; import { Store } from "$ts/writable"; import type { AppProcessData } from "$types/apps/app"; -import type { SetupState } from "./store"; +import type { SetupState } from "./types"; export class TotpSetupGuiRuntime extends AppProcess implements ITotpSetupGuiRuntime { public code = Store(""); diff --git a/src/apps/components/totpsetupgui/store.ts b/src/apps/components/totpsetupgui/types.ts similarity index 100% rename from src/apps/components/totpsetupgui/store.ts rename to src/apps/components/totpsetupgui/types.ts diff --git a/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts b/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts index fd44175c9..61405eee0 100644 --- a/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts +++ b/src/interfaces/runtimes/ITotpSetupGuiRuntime.ts @@ -1,4 +1,4 @@ -import type { SetupState } from "$apps/components/totpsetupgui/store"; +import type { SetupState } from "$apps/components/totpsetupgui/types"; import type { IAppProcess } from "$interfaces/IAppProcess"; import type { ReadableStore } from "$types/shared/writable"; From 822efa4caae5f06371ed95b95c8101896bfc0d13 Mon Sep 17 00:00:00 2001 From: Blockyheadman <80011716+Blockyheadman@users.noreply.github.com> Date: Thu, 13 Aug 2026 15:33:38 -0500 Subject: [PATCH 4/4] null references are fun to delete and resuscitate --- src/apps/core/newloginapp/runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/apps/core/newloginapp/runtime.ts b/src/apps/core/newloginapp/runtime.ts index 0ea3bcee6..25df0ec0e 100644 --- a/src/apps/core/newloginapp/runtime.ts +++ b/src/apps/core/newloginapp/runtime.ts @@ -132,7 +132,7 @@ export class NewLoginAppRuntime extends AppProcess implements INewLoginAppRuntim this.Persistence.update((v) => { const userConnector = Server.GetConn("UserConnector", ""); const persistence: LoginPersistenceUser = { - displayName: info.username, + displayName: info.preferences?.account?.displayName ?? info.username, username: info.username, userId: info._id, profilePictureUrl: userConnector.PictureUrl(info._id),