atagen

malice

public
Star0
Watch0
a10d41eaedf6c1f015d3253c02314ce4cc370c47
2
ssh://brewery@pls.lobotomise.me:33/atagen/malice.git

Blame: web/src/lib/protection-model.ts

4929dcd34937atagen2026-10-26 04:43 UTC1
import type { EncryptionState } from './types';
4929dcd34937atagen2026-10-26 04:43 UTC2
4929dcd34937atagen2026-10-26 04:43 UTC3
export type RecoveryPrompt = 'recover' | 'setup';
4929dcd34937atagen2026-10-26 04:43 UTC4
4929dcd34937atagen2026-10-26 04:43 UTC5
export interface InstallContext {
4929dcd34937atagen2026-10-26 04:43 UTC6
  device: boolean;
4929dcd34937atagen2026-10-26 04:43 UTC7
  standalone: boolean;
4929dcd34937atagen2026-10-26 04:43 UTC8
}
4929dcd34937atagen2026-10-26 04:43 UTC9
4929dcd34937atagen2026-10-26 04:43 UTC10
export interface PersistResult {
4929dcd34937atagen2026-10-26 04:43 UTC11
  persisted: boolean;
4929dcd34937atagen2026-10-26 04:43 UTC12
  usage: number | null;
4929dcd34937atagen2026-10-26 04:43 UTC13
  quota: number | null;
4929dcd34937atagen2026-10-26 04:43 UTC14
}
4929dcd34937atagen2026-10-26 04:43 UTC15
4929dcd34937atagen2026-10-26 04:43 UTC16
export interface StorageLike {
4929dcd34937atagen2026-10-26 04:43 UTC17
  getItem(key: string): string | null;
4929dcd34937atagen2026-10-26 04:43 UTC18
  setItem(key: string, value: string): void;
4929dcd34937atagen2026-10-26 04:43 UTC19
}
4929dcd34937atagen2026-10-26 04:43 UTC20
4929dcd34937atagen2026-10-26 04:43 UTC21
export interface PersistManager {
4929dcd34937atagen2026-10-26 04:43 UTC22
  persisted?(): Promise<boolean>;
4929dcd34937atagen2026-10-26 04:43 UTC23
  persist?(): Promise<boolean>;
4929dcd34937atagen2026-10-26 04:43 UTC24
  estimate?(): Promise<{ usage?: number; quota?: number }>;
4929dcd34937atagen2026-10-26 04:43 UTC25
}
4929dcd34937atagen2026-10-26 04:43 UTC26
4929dcd34937atagen2026-10-26 04:43 UTC27
export function canDismissRecovery(ctx: InstallContext): boolean {
4929dcd34937atagen2026-10-26 04:43 UTC28
  return ctx.device && !ctx.standalone;
4929dcd34937atagen2026-10-26 04:43 UTC29
}
4929dcd34937atagen2026-10-26 04:43 UTC30
4929dcd34937atagen2026-10-26 04:43 UTC31
export function recoveryPrompt(state: EncryptionState | null, ctx: InstallContext, dismissed: boolean): RecoveryPrompt | null {
4929dcd34937atagen2026-10-26 04:43 UTC32
  if (!state) return null;
4929dcd34937atagen2026-10-26 04:43 UTC33
  if (state.recovery === 'Incomplete') return 'recover';
4929dcd34937atagen2026-10-26 04:43 UTC34
  if (state.recovery === 'Disabled') return dismissed && canDismissRecovery(ctx) ? null : 'setup';
4929dcd34937atagen2026-10-26 04:43 UTC35
  return null;
4929dcd34937atagen2026-10-26 04:43 UTC36
}
4929dcd34937atagen2026-10-26 04:43 UTC37
4929dcd34937atagen2026-10-26 04:43 UTC38
export function dismissalKey(kind: 'recovery' | 'storage', account: string): string {
4929dcd34937atagen2026-10-26 04:43 UTC39
  return `malice.dismissed.${kind}.${account}`;
4929dcd34937atagen2026-10-26 04:43 UTC40
}
4929dcd34937atagen2026-10-26 04:43 UTC41
4929dcd34937atagen2026-10-26 04:43 UTC42
export function isDismissed(store: StorageLike, kind: 'recovery' | 'storage', account: string): boolean {
4929dcd34937atagen2026-10-26 04:43 UTC43
  try {
4929dcd34937atagen2026-10-26 04:43 UTC44
    return store.getItem(dismissalKey(kind, account)) === '1';
4929dcd34937atagen2026-10-26 04:43 UTC45
  } catch {
4929dcd34937atagen2026-10-26 04:43 UTC46
    return false;
4929dcd34937atagen2026-10-26 04:43 UTC47
  }
4929dcd34937atagen2026-10-26 04:43 UTC48
}
4929dcd34937atagen2026-10-26 04:43 UTC49
4929dcd34937atagen2026-10-26 04:43 UTC50
export function setDismissed(store: StorageLike, kind: 'recovery' | 'storage', account: string): void {
4929dcd34937atagen2026-10-26 04:43 UTC51
  try {
4929dcd34937atagen2026-10-26 04:43 UTC52
    store.setItem(dismissalKey(kind, account), '1');
4929dcd34937atagen2026-10-26 04:43 UTC53
  } catch {
4929dcd34937atagen2026-10-26 04:43 UTC54
    // dismissal then lasts only for this page load
4929dcd34937atagen2026-10-26 04:43 UTC55
  }
4929dcd34937atagen2026-10-26 04:43 UTC56
}
4929dcd34937atagen2026-10-26 04:43 UTC57
4929dcd34937atagen2026-10-26 04:43 UTC58
export async function requestPersistence(manager: PersistManager | undefined): Promise<PersistResult | null> {
4929dcd34937atagen2026-10-26 04:43 UTC59
  if (!manager?.persist || !manager.persisted) return null;
4929dcd34937atagen2026-10-26 04:43 UTC60
  let persisted = await manager.persisted();
4929dcd34937atagen2026-10-26 04:43 UTC61
  if (!persisted) persisted = await manager.persist();
4929dcd34937atagen2026-10-26 04:43 UTC62
  const estimate = manager.estimate ? await manager.estimate().catch(() => null) : null;
4929dcd34937atagen2026-10-26 04:43 UTC63
  return { persisted, usage: estimate?.usage ?? null, quota: estimate?.quota ?? null };
4929dcd34937atagen2026-10-26 04:43 UTC64
}