Files
sb-front/src/components/AppLockScreen.vue
T
ByungCheol bac3ce1ded
CI / build (push) Failing after 10m50s
feat: 앱 잠금(PIN) 추가 — 가계부 보안 강화
- 자체 구현(네이티브 플러그인 없음): PIN은 SHA-256 해시만 저장, 기본 OFF 옵트인
- 앱 시작(저장 세션 재진입)·백그라운드 복귀 시 잠금 화면 노출
- 설정에 앱 잠금 토글 + PIN 설정(입력→확인 2단계) 모달
- 갇힘 방지: 잠금 화면에서 'PIN 분실 → 로그아웃'(잠금 해제 후 로그아웃)
- 신규/민감정보 앱 신뢰도 향상

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 08:45:38 +09:00

97 lines
2.2 KiB
Vue

<script setup>
import { ref } from 'vue'
import { appLock, PIN_LENGTH } from '@/composables/appLock'
import { useAuthStore } from '@/stores/auth'
import PinPad from '@/components/PinPad.vue'
const auth = useAuthStore()
const pin = ref('')
const error = ref(false)
async function onComplete(p) {
if (await appLock.verify(p)) {
pin.value = ''
error.value = false
appLock.unlock()
} else {
error.value = true
pin.value = ''
}
}
function onInput(v) {
pin.value = v
error.value = false
}
async function forgot() {
// PIN 분실 → 잠금 해제 + 로그아웃(재로그인 후 다시 설정). 갇힘 방지.
appLock.disable()
await auth.logout()
appLock.unlock()
}
</script>
<template>
<div class="lock-screen">
<div class="lock-inner">
<div class="lock-logo">🐷</div>
<h1 class="lock-title">돈돼지 가계부</h1>
<p class="lock-sub" :class="{ err: error }">
{{ error ? 'PIN이 일치하지 않아요' : 'PIN을 입력하세요' }}
</p>
<PinPad :value="pin" :length="PIN_LENGTH" class="lock-pad" @update:value="onInput" @complete="onComplete" />
<button type="button" class="lock-forgot" @click="forgot">PIN을 잊으셨나요? 로그아웃</button>
</div>
</div>
</template>
<style scoped>
.lock-screen {
position: fixed;
inset: 0;
z-index: 3000;
display: flex;
align-items: center;
justify-content: center;
padding: calc(env(safe-area-inset-top, 0) + 1rem) 1rem calc(env(safe-area-inset-bottom, 0) + 1rem);
background: var(--color-background);
}
.lock-inner {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
}
.lock-logo {
font-size: 2.6rem;
}
.lock-title {
margin-top: 0.4rem;
font-size: 1.25rem;
color: var(--color-heading);
}
.lock-sub {
margin-top: 0.6rem;
margin-bottom: 1.8rem;
font-size: 0.92rem;
opacity: 0.7;
}
.lock-sub.err {
color: #c0392b;
opacity: 1;
font-weight: 600;
}
.lock-forgot {
margin-top: 2rem;
border: 0;
background: transparent;
color: var(--color-text);
opacity: 0.6;
font-size: 0.85rem;
text-decoration: underline;
cursor: pointer;
}
.lock-forgot:hover {
opacity: 0.9;
}
</style>