import { reactive } from 'vue' // 앱 잠금(PIN). 자체 구현 — 네이티브 플러그인 없이 동작. // PIN 은 평문 저장하지 않고 SHA-256 해시만 보관. 기본 비활성(옵트인). // 갇힘 방지: 잠금 화면에서 'PIN 분실 → 로그아웃' 으로 disable + 로그아웃 가능. const KEY_ENABLED = 'applock:enabled' const KEY_HASH = 'applock:hash' export const PIN_LENGTH = 4 const state = reactive({ enabled: localStorage.getItem(KEY_ENABLED) === '1', locked: false, }) // 카메라/갤러리/공유 등 앱 내 네이티브 동작을 호출하면 웹뷰가 잠깐 백그라운드로 // 인식돼 잠금이 걸리는 오작동을 막기 위한 "잠금 일시중지" 창(timestamp). let suppressUntil = 0 async function hashPin(pin) { const data = new TextEncoder().encode('dondwaeji-applock:' + pin) const buf = await crypto.subtle.digest('SHA-256', data) return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, '0')).join('') } export const appLock = { state, /** PIN 설정 + 잠금 활성화 */ async setPin(pin) { localStorage.setItem(KEY_HASH, await hashPin(pin)) localStorage.setItem(KEY_ENABLED, '1') state.enabled = true }, /** 입력 PIN 검증 */ async verify(pin) { const stored = localStorage.getItem(KEY_HASH) return !!stored && (await hashPin(pin)) === stored }, /** 잠금 해제(설정 끄기) */ disable() { localStorage.removeItem(KEY_HASH) localStorage.removeItem(KEY_ENABLED) state.enabled = false state.locked = false }, /** 잠금 걸기(활성화 + 일시중지 창 밖일 때만) */ lock() { if (Date.now() < suppressUntil) return // 네이티브 동작 복귀 — 잠그지 않음 if (state.enabled) state.locked = true }, /** 다음 백그라운드 전환을 잠그지 않음(카메라/갤러리/공유 호출 직전에 사용) */ suppressLock(ms = 60000) { suppressUntil = Date.now() + ms }, /** 일시중지 창 해제(앱으로 복귀 시) */ clearSuppress() { suppressUntil = 0 }, /** 잠금 풀기(이번 세션) */ unlock() { state.locked = false }, /** 저장된 세션이 있는지(앱 시작 시 잠금 여부 판단용) */ hasSession() { return !!localStorage.getItem('token') }, }