Serialize Google connect and disconnect; consume connect state once
A disconnect read the stored refresh token, revoked it at Google, then deleted the row only if it still held that token. Google revokes the whole grant, so a reconnect whose token was issued before that revoke was kept as connected with a dead token. Connect's exchange-and-store and disconnect's read-revoke-delete now hold one mutex across the Google request and the database write, and the delete is unconditional (the conditional delete and ErrChanged are gone: the lock is the one guard). The connect cookie was single-use only in that the browser was asked to drop it; a saved copy verified again until it expired. The service now keeps each started connect's state in memory until the cookie expires and the callback consumes it, so a replayed cookie is refused as bad state. The fake Google now issues a distinct refresh token per exchange, revokes the whole grant like Google, and can hold a token or revoke request so tests can interleave a reconnect and a disconnect. Maestro task 1e9d7850-3a09-4572-b8a1-cb18cd4774cb (MQ125-01, MQ125-02). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,20 +10,14 @@ import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
const deleteIntegrationsGoogle = `-- name: DeleteIntegrationsGoogle :execrows
|
||||
const deleteIntegrationsGoogle = `-- name: DeleteIntegrationsGoogle :exec
|
||||
DELETE FROM integrations_google
|
||||
WHERE id = 1 AND refresh_token_ct = ?
|
||||
WHERE id = 1
|
||||
`
|
||||
|
||||
// Deletes the row only while it still holds refresh_token_ct, so a
|
||||
// connection made after the caller read the row is kept. Returns the number
|
||||
// of rows deleted.
|
||||
func (q *Queries) DeleteIntegrationsGoogle(ctx context.Context, refreshTokenCt []byte) (int64, error) {
|
||||
result, err := q.db.ExecContext(ctx, deleteIntegrationsGoogle, refreshTokenCt)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return result.RowsAffected()
|
||||
func (q *Queries) DeleteIntegrationsGoogle(ctx context.Context) error {
|
||||
_, err := q.db.ExecContext(ctx, deleteIntegrationsGoogle)
|
||||
return err
|
||||
}
|
||||
|
||||
const getAISettings = `-- name: GetAISettings :one
|
||||
|
||||
Reference in New Issue
Block a user