package store import ( "context" "errors" "time" ) // GPGKey is one signing key an account has published, so a signature on a commit can be checked. type GPGKey struct { ID int64 Account string Fingerprint string UID string Armor string Created time.Time } // AddGPGKey stores a key already parsed, since parsing needs gpg and this package needs none. func (db *DB) AddGPGKey(ctx context.Context, account, fingerprint, uid, armor string) error { _, err := db.ExecContext(ctx, `INSERT INTO gpgkeys (account, fingerprint, uid, armor, created_at) VALUES (?, ?, ?, ?, ?)`, account, fingerprint, uid, armor, now().Unix()) return err } // GPGKeys lists one account's keys, newest last, the way the keys page draws them. func (db *DB) GPGKeys(ctx context.Context, account string) ([]GPGKey, error) { rows, err := db.QueryContext(ctx, `SELECT id, account, fingerprint, uid, armor, created_at FROM gpgkeys WHERE account = ? ORDER BY id`, account) if err != nil { return nil, err } defer rows.Close() var out []GPGKey for rows.Next() { var k GPGKey var created int64 if err := rows.Scan(&k.ID, &k.Account, &k.Fingerprint, &k.UID, &k.Armor, &created); err != nil { return nil, err } k.Created = time.Unix(created, 0) out = append(out, k) } return out, rows.Err() } // AllGPGKeys is every key on the server, because one keyring verifies every commit. func (db *DB) AllGPGKeys(ctx context.Context) ([]GPGKey, error) { rows, err := db.QueryContext(ctx, `SELECT id, account, fingerprint, uid, armor, created_at FROM gpgkeys ORDER BY id`) if err != nil { return nil, err } defer rows.Close() var out []GPGKey for rows.Next() { var k GPGKey var created int64 if err := rows.Scan(&k.ID, &k.Account, &k.Fingerprint, &k.UID, &k.Armor, &created); err != nil { return nil, err } k.Created = time.Unix(created, 0) out = append(out, k) } return out, rows.Err() } // DeleteGPGKey revokes one key, and only its own account may. func (db *DB) DeleteGPGKey(ctx context.Context, account string, id int64) error { res, err := db.ExecContext(ctx, `DELETE FROM gpgkeys WHERE id = ? AND account = ?`, id, account) if err != nil { return err } if n, _ := res.RowsAffected(); n == 0 { return errors.New("no such key") } return nil } // AccountForGPGKey names who published a key, which is the only claim about a signature barerepo owns. func (db *DB) AccountForGPGKey(ctx context.Context, fingerprint string) (string, error) { var account string err := db.QueryRowContext(ctx, `SELECT account FROM gpgkeys WHERE fingerprint = ?`, fingerprint).Scan(&account) return account, err }