// mirrortoken.go is the access token a Git mirror's fetches send, for
// an upstream that is not public (a private GitHub repository).
//
// It is sealed the way the uv round's password is (secret.go): every
// fetch replays it, so a one-way hash cannot hold it, and a copy of
// oltp.db alone must not yield it. MirrorGitToken is its one reader, and
// no op returns it.
package oltp
import (
"database/sql"
"errors"
"fmt"
)
// SetMirrorGitToken stores the token repo's Git mirror fetches with,
// sealed; an empty token clears it, and the fetches go anonymously. The
// upstream the token belongs to is the row's URL, which a Git mirror
// never changes, and SetMirror drops the token if it ever did.
func (d *DB) SetMirrorGitToken(repo, token string) error {
sealed := ""
if token != "" {
var err error
if sealed, err = d.seal.seal(token); err != nil {
return err
}
}
res, err := d.w.Exec(`UPDATE mirror SET git_token_enc = ? WHERE repo = ? AND kind = ?`, sealed, repo, MirrorGit)
if err != nil {
return err
}
if n, _ := res.RowsAffected(); n == 0 {
return fmt.Errorf("oltp: %s is not a Git mirror", repo)
}
return nil
}
// MirrorGitToken is repo's Git mirror token unsealed, "" when it holds
// none or has no mirror. Its one caller is the fetch.
func (d *DB) MirrorGitToken(repo string) (string, error) {
var sealed string
err := d.db.QueryRow(`SELECT git_token_enc FROM mirror WHERE repo = ?`, repo).Scan(&sealed)
if errors.Is(err, sql.ErrNoRows) {
return "", nil
}
if err != nil {
return "", err
}
if sealed == "" {
return "", nil
}
return d.seal.open(sealed)
}