# 機能設計書：アカウントロック

## 1. 機能概要

### 1.1 機能の目的
アカウントロック機能は、ブルートフォース攻撃からユーザーアカウントを保護する機能である。一定回数のログイン失敗でアカウントを一時的にロックし、攻撃者がパスワードを推測することを防ぐ。

### 1.2 機能の範囲
- ログイン試行回数の追跡
- アカウントのロックとロック解除
- ロック時間の管理
- 管理者によるアカウントロック解除

### 1.3 関連画面
| 画面ID | 画面名 | 関連操作 |
|--------|--------|----------|
| AUTH-001 | ログイン画面 | login（ロック状態表示） |
| ADM-040 | ユーザー管理 | unlock |

---

## 2. 機能仕様

### 2.1 入力仕様

#### 2.1.1 ロック設定
```typescript
interface LockConfig {
  maxLoginAttempts?: number;  // 最大ログイン試行回数（デフォルト: 5、0で無効）
  lockTime?: number;          // ロック時間（ms、デフォルト: 600000 = 10分）
}
```

#### 2.1.2 Unlock操作
| パラメータ | 型 | 必須 | 説明 |
|-----------|-----|------|------|
| collection | string | Yes | 認証コレクションのslug |
| email | string | Yes* | メールアドレス（emailまたはusernameのいずれか） |
| username | string | Yes* | ユーザー名 |
| overrideAccess | boolean | No | アクセス制御のオーバーライド |

### 2.2 出力仕様

#### 2.2.1 Unlock操作の戻り値
```typescript
// 成功時: true
// 失敗時: Forbidden（ユーザー未発見または権限なし）
type UnlockResult = boolean
```

### 2.3 処理フロー

```
[ログイン失敗時の試行回数インクリメントフロー（incrementLoginAttempts）]
1. maxLoginAttempts設定の確認
2. lockUntilの確認
   - 期限切れの場合: ロック解除、loginAttempts=1にリセット
3. loginAttemptsをインクリメント（$inc: 1）
4. maxLoginAttempts到達チェック
   - 到達: lockUntilを設定（現在時刻 + lockTime）
5. 並列リクエスト対応
   - 複数リクエストで最大試行に達した場合のロック確認
6. useSessions有効時
   - 直近20秒以内に作成されたセッションを削除
   - （ブルートフォース攻撃で偶然成功したセッションの無効化）
```

```
[ログイン時のロック確認フロー（checkLoginPermission）]
1. ユーザー存在確認
   - 不存在: AuthenticationError
2. lockUntilの確認
   - isUserLocked関数でロック状態チェック
3. ロック中の場合
   - LockedAuth エラーを発生
```

```
[ログイン成功時のリセットフロー（resetLoginAttempts）]
1. loginAttempts=0にリセット
2. lockUntil=nullに設定
3. updatedAtを更新
```

```
[Unlock処理フロー（unlockOperation）]
1. disableLocalStrategyチェック
2. email/usernameの必須チェック
3. beforeOperation フック実行
4. トランザクション開始
5. アクセス制御チェック（overrideAccess=false時）
6. email/usernameでユーザー検索
   - trash除外
7. ユーザーが見つからない場合
   - Forbidden エラー
8. resetLoginAttempts呼び出し
   - loginAttempts=0
   - lockUntil=null
9. トランザクションコミット
10. afterOperation フック実行
11. true を返却
```

### 2.4 バリデーションルール
- maxLoginAttempts: 0以上の整数
- lockTime: 正の整数（ミリ秒）

### 2.5 エラーハンドリング
| エラーコード | 説明 | HTTPステータス |
|-------------|------|---------------|
| LockedAuth | アカウントロック中 | 401 |
| Forbidden | ユーザー未発見または権限なし | 403 |
| APIError | email/username欠落 | 400 |

---

## 3. データ設計

### 3.1 ロック関連フィールド
```typescript
// 認証コレクションに自動追加
interface LockFields {
  loginAttempts?: number;  // ログイン試行回数
  lockUntil?: string;      // ロック解除日時（ISO8601）
}
```

### 3.2 ロック状態判定
```typescript
// isUserLocked関数の判定ロジック
function isUserLocked(lockUntil: Date | string): boolean {
  if (!lockUntil) return false;
  const lockDate = new Date(lockUntil);
  return lockDate > new Date();  // 現在時刻より後ならロック中
}
```

---

## 4. コードリーディングガイド

### 4.1 推奨読解順序

1. **ログイン試行管理**
   - `/packages/payload/src/auth/strategies/local/incrementLoginAttempts.ts`
   - **14-17行目**: 引数定義（collection, payload, user）
   - **18-22行目**: lockTime, maxLoginAttemptsの取得
   - **28-44行目**: 期限切れロックのリセット
   - **45-58行目**: loginAttempts インクリメントとロック設定
   - **60-72行目**: データベース更新
   - **79-108行目**: 並列リクエスト対応のロック再確認
   - **110-151行目**: セッション無効化処理

2. **ロック状態確認**
   - `/packages/payload/src/auth/isUserLocked.ts`
   - 単純な日時比較でロック状態を判定

3. **ロック解除処理**
   - `/packages/payload/src/auth/operations/unlock.ts`
   - **22-27行目**: Arguments型定義
   - **29-59行目**: 入力検証とbeforeOperation
   - **61-82行目**: アクセス制御
   - **84-114行目**: ユーザー検索と検証
   - **118-124行目**: resetLoginAttempts呼び出し
   - **131-143行目**: afterOperation

4. **リセット処理**
   - `/packages/payload/src/auth/strategies/local/resetLoginAttempts.ts`
   - loginAttempts=0, lockUntil=nullへの更新

### 4.2 プログラム呼び出し階層図

```
payload.login()
  |
  +-- checkLoginPermission()
  |     +-- isUserLocked()
  |     +-- [Locked] --> LockedAuth Error
  |
  +-- authenticateLocalStrategy()
  |
  +-- [認証失敗時]
  |     +-- incrementLoginAttempts()
  |           |
  |           +-- [期限切れロック] --> リセット
  |           +-- loginAttempts++
  |           +-- [maxLoginAttempts到達] --> lockUntil設定
  |           +-- [並列リクエスト対応]
  |           +-- [セッション無効化]
  |
  +-- [認証成功時]
        +-- resetLoginAttempts()
```

```
payload.unlock()
  |
  +-- buildBeforeOperation()
  |
  +-- initTransaction()
  |
  +-- executeAccess()
  |
  +-- payload.db.findOne() [ユーザー検索]
  |
  +-- [Not Found] --> Forbidden
  |
  +-- resetLoginAttempts()
  |
  +-- commitTransaction()
  |
  +-- buildAfterOperation()
```

### 4.3 データフロー図

```
[ログイン失敗]
       |
       v
+------------------+
| maxLoginAttempts |
| チェック         |
+------------------+
       |
       +-- 無効 (0) --> 何もしない
       |
       v
+------------------+
| lockUntil期限切れ|
| チェック         |
+------------------+
       |
       +-- 期限切れ --> リセット (loginAttempts=1)
       |
       v
+------------------+
| loginAttempts++  |
+------------------+
       |
       v
+------------------+
| maxLoginAttempts |
| 到達チェック     |
+------------------+
       |
       +-- 到達 --> lockUntil設定
       |
       v
[ユーザー更新完了]
```

```
[Unlock]
       |
       v
+------------------+
| Access Control   |
+------------------+
       |
       +-- 権限なし --> Forbidden
       |
       v
+------------------+
| ユーザー検索     |
+------------------+
       |
       +-- Not Found --> Forbidden
       |
       v
+------------------+
| resetLoginAttempts|
+------------------+
       |
       v
[true返却]
```

### 4.4 関連ファイル一覧

| ファイルパス | 種別 | 役割 |
|-------------|------|------|
| `/packages/payload/src/auth/strategies/local/incrementLoginAttempts.ts` | 処理 | 試行回数インクリメント |
| `/packages/payload/src/auth/strategies/local/resetLoginAttempts.ts` | 処理 | 試行回数リセット |
| `/packages/payload/src/auth/isUserLocked.ts` | ユーティリティ | ロック状態判定 |
| `/packages/payload/src/auth/operations/unlock.ts` | 処理 | アカウントロック解除 |
| `/packages/payload/src/auth/operations/login.ts` | 処理 | ログイン処理（ロック確認含む） |
| `/packages/payload/src/auth/types.ts` | 型定義 | maxLoginAttempts, lockTime定義 |

---

## 5. 設計上の考慮事項

### 5.1 パフォーマンス考慮
- $incオペレータによるアトミックな更新
- 並列リクエスト対応による競合状態の解決

### 5.2 セキュリティ考慮
- ブルートフォース攻撃の緩和（試行回数制限）
- 並列攻撃への対応（20秒以内のセッション無効化）
- ユーザー不存在時も同様のエラーメッセージ（情報漏洩防止）
- 管理者のみがunlock操作を実行可能（access.unlock）

### 5.3 拡張性考慮
- maxLoginAttempts=0でロック機能を無効化
- lockTimeでロック時間をカスタマイズ
- access.unlockでロック解除権限をカスタマイズ

---

## 6. 変更履歴

| 日付 | バージョン | 変更内容 | 担当者 |
|------|-----------|----------|--------|
| 2026-03-01 | 1.0.0 | 初版作成 | AI |
