Add SMS consent logging for Twilio compliance
Log phone, IP, and user agent to sms_consents table before sending verification SMS. Add disclosure text to login form. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,11 @@ func (s *Server) handleLoginSubmit(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("failed to send verification email to %s: %v", identifier, err)
|
||||
}
|
||||
} else {
|
||||
s.q.CreateSmsConsent(r.Context(), db.CreateSmsConsentParams{
|
||||
Phone: identifier,
|
||||
IpAddress: r.RemoteAddr,
|
||||
UserAgent: r.UserAgent(),
|
||||
})
|
||||
if err := sendVerificationSMS(identifier, code); err != nil {
|
||||
log.Printf("failed to send verification SMS to %s: %v", identifier, err)
|
||||
}
|
||||
|
||||
@@ -54,6 +54,14 @@ type Slot struct {
|
||||
SortOrder int64
|
||||
}
|
||||
|
||||
type SmsConsent struct {
|
||||
ID int64
|
||||
Phone string
|
||||
IpAddress string
|
||||
UserAgent string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID int64
|
||||
Phone sql.NullString
|
||||
|
||||
@@ -132,3 +132,6 @@ SELECT * FROM rsvps WHERE id = ?;
|
||||
|
||||
-- name: UpdateRsvp :exec
|
||||
UPDATE rsvps SET name = ?, note = ?, plus_one = ? WHERE id = ?;
|
||||
|
||||
-- name: CreateSmsConsent :exec
|
||||
INSERT INTO sms_consents (phone, ip_address, user_agent) VALUES (?, ?, ?);
|
||||
|
||||
@@ -181,6 +181,21 @@ func (q *Queries) CreateSlot(ctx context.Context, arg CreateSlotParams) (Slot, e
|
||||
return i, err
|
||||
}
|
||||
|
||||
const createSmsConsent = `-- name: CreateSmsConsent :exec
|
||||
INSERT INTO sms_consents (phone, ip_address, user_agent) VALUES (?, ?, ?)
|
||||
`
|
||||
|
||||
type CreateSmsConsentParams struct {
|
||||
Phone string
|
||||
IpAddress string
|
||||
UserAgent string
|
||||
}
|
||||
|
||||
func (q *Queries) CreateSmsConsent(ctx context.Context, arg CreateSmsConsentParams) error {
|
||||
_, err := q.db.ExecContext(ctx, createSmsConsent, arg.Phone, arg.IpAddress, arg.UserAgent)
|
||||
return err
|
||||
}
|
||||
|
||||
const createUserByEmail = `-- name: CreateUserByEmail :one
|
||||
INSERT INTO users (email, name) VALUES (?, '') RETURNING id, phone, email, name, created_at
|
||||
`
|
||||
|
||||
@@ -22,6 +22,14 @@ func runMigrations(database *sql.DB) {
|
||||
`DELETE FROM rsvps WHERE id NOT IN (SELECT MIN(id) FROM rsvps GROUP BY event_id, name COLLATE NOCASE)`,
|
||||
// Plus-one tracking for RSVPs.
|
||||
`ALTER TABLE rsvps ADD COLUMN plus_one INTEGER NOT NULL DEFAULT 0`,
|
||||
// SMS consent logging for Twilio compliance.
|
||||
`CREATE TABLE IF NOT EXISTS sms_consents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
phone TEXT NOT NULL,
|
||||
ip_address TEXT NOT NULL DEFAULT '',
|
||||
user_agent TEXT NOT NULL DEFAULT '',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
)`,
|
||||
}
|
||||
for _, m := range migrations {
|
||||
_, err := database.Exec(m)
|
||||
|
||||
@@ -59,6 +59,14 @@ CREATE TABLE IF NOT EXISTS verification_codes (
|
||||
used INTEGER NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS sms_consents (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
phone TEXT NOT NULL,
|
||||
ip_address TEXT NOT NULL DEFAULT '',
|
||||
user_agent TEXT NOT NULL DEFAULT '',
|
||||
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_slots_event ON slots(event_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_claims_slot ON claims(slot_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_rsvps_event ON rsvps(event_id);
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
<label>Email or phone</label>
|
||||
<input type="text" name="identifier" placeholder="you@example.com or (555) 123-4567" required autofocus>
|
||||
</div>
|
||||
<p style="font-family:'DM Mono',monospace;font-size:0.7rem;color:#777;margin-top:12px;line-height:1.5;">
|
||||
By entering a phone number, you consent to receive a one-time verification code via SMS. Msg & data rates may apply. No marketing messages will be sent.
|
||||
</p>
|
||||
<button class="btn-submit" type="submit">Send code ↗</button>
|
||||
</form>
|
||||
{{else}}
|
||||
|
||||
Reference in New Issue
Block a user