(socketPath string, requireTouchPerSign bool, ttlSeconds int)
| 21 | func Start(socketPath string) error { return StartWithOptions(socketPath, true, 0) } |
| 22 | |
| 23 | func StartWithOptions(socketPath string, requireTouchPerSign bool, ttlSeconds int) error { |
| 24 | log.Info("启动 fssh SSH 认证代理", nil) |
| 25 | |
| 26 | if socketPath == "" { |
| 27 | socketPath = defaultSocket() |
| 28 | } |
| 29 | |
| 30 | // 获取认证提供者(用于显示认证模式) |
| 31 | provider, err := auth.GetAuthProvider(ttlSeconds) |
| 32 | if err != nil { |
| 33 | return fmt.Errorf("初始化认证提供者失败: %w", err) |
| 34 | } |
| 35 | |
| 36 | log.Info("认证模式", map[string]interface{}{ |
| 37 | "mode": provider.Mode(), |
| 38 | }) |
| 39 | |
| 40 | // OTP 模式:启动时预先解锁 |
| 41 | if provider.Mode() == auth.ModeOTP && requireTouchPerSign { |
| 42 | if err := preUnlockOTP(); err != nil { |
| 43 | return err |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | _ = os.Remove(socketPath) |
| 48 | if err := os.MkdirAll(filepath.Dir(socketPath), 0700); err != nil { |
| 49 | return err |
| 50 | } |
| 51 | ln, err := net.Listen("unix", socketPath) |
| 52 | if err != nil { |
| 53 | return err |
| 54 | } |
| 55 | |
| 56 | var ag xagent.Agent |
| 57 | if requireTouchPerSign { |
| 58 | sa, err := newSecureAgentWithTTL(ttlSeconds) |
| 59 | if err != nil { ln.Close(); return err } |
| 60 | ag = sa |
| 61 | log.Info("安全模式: 每次签名需要认证", map[string]interface{}{ |
| 62 | "ttl_seconds": ttlSeconds, |
| 63 | }) |
| 64 | } else { |
| 65 | // 便利模式:启动时解密所有私钥 |
| 66 | mk, err := provider.UnlockMasterKey() |
| 67 | if err != nil { ln.Close(); return err } |
| 68 | keyring := xagent.NewKeyring() |
| 69 | dir := store.KeysDir() |
| 70 | entries, err := os.ReadDir(dir) |
| 71 | if err == nil { |
| 72 | for _, e := range entries { |
| 73 | if e.IsDir() || filepath.Ext(e.Name()) != ".enc" { continue } |
| 74 | alias := e.Name()[:len(e.Name())-4] |
| 75 | rec, err := store.LoadDecryptedRecord(alias, mk) |
| 76 | if err != nil { continue } |
| 77 | pk, err := x509.ParsePKCS8PrivateKey(rec.PKCS8DER) |
| 78 | if err != nil { continue } |
| 79 | _ = keyring.Add(xagent.AddedKey{PrivateKey: pk, Comment: rec.Alias}) |
| 80 | } |
no test coverage detected