Files
mailgoserver/internal/db/crud_mailbox_smime.go
T

112 lines
4.1 KiB
Go

package db
import (
"database/sql"
"errors"
"time"
)
// CreateSMIMEIdentity adds a new S/MIME identity for a mailbox — a mailbox may hold
// several at once (see esrv_mailbox_smime_identities in schema.go).
func (d *DB) CreateSMIMEIdentity(mailboxID int64, certPEM, keyPEM string, notAfter time.Time) (int64, error) {
res, err := d.Exec(`
INSERT INTO esrv_mailbox_smime_identities (mailbox_id, cert_pem, key_pem, not_after)
VALUES (?, ?, ?, ?)
`, mailboxID, certPEM, keyPEM, notAfter)
if err != nil {
return 0, err
}
return res.LastInsertId()
}
// ListSMIMEIdentities returns a mailbox's S/MIME identities, most recent first.
func (d *DB) ListSMIMEIdentities(mailboxID int64) ([]MailboxSMIMEIdentity, error) {
rows, err := d.Query(`SELECT id, mailbox_id, cert_pem, key_pem, not_after, created_at
FROM esrv_mailbox_smime_identities WHERE mailbox_id = ? ORDER BY created_at DESC, id DESC`, mailboxID)
if err != nil {
return nil, err
}
defer rows.Close()
var out []MailboxSMIMEIdentity
for rows.Next() {
var id MailboxSMIMEIdentity
if err := rows.Scan(&id.ID, &id.MailboxID, &id.CertPEM, &id.KeyPEM, &id.NotAfter, &id.CreatedAt); err != nil {
return nil, err
}
out = append(out, id)
}
return out, rows.Err()
}
// GetSMIMEIdentity returns nil, nil if no such identity exists for this mailbox —
// scoped to mailboxID so one mailbox owner can't reach another's identity by
// guessing its ID.
func (d *DB) GetSMIMEIdentity(mailboxID, identityID int64) (*MailboxSMIMEIdentity, error) {
row := d.QueryRow(`SELECT id, mailbox_id, cert_pem, key_pem, not_after, created_at
FROM esrv_mailbox_smime_identities WHERE mailbox_id = ? AND id = ?`, mailboxID, identityID)
var id MailboxSMIMEIdentity
if err := row.Scan(&id.ID, &id.MailboxID, &id.CertPEM, &id.KeyPEM, &id.NotAfter, &id.CreatedAt); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, err
}
return &id, nil
}
// DeleteSMIMEIdentity removes one identity, scoped to mailboxID.
func (d *DB) DeleteSMIMEIdentity(mailboxID, identityID int64) error {
_, err := d.Exec(`DELETE FROM esrv_mailbox_smime_identities WHERE mailbox_id = ? AND id = ?`, mailboxID, identityID)
return err
}
// UpsertSMIMEContact adds a contact certificate, replacing any existing certificate
// already on file for that email (e.g. after the contact renews their cert).
func (d *DB) UpsertSMIMEContact(mailboxID int64, email, certPEM string) error {
_, err := d.Exec(`
INSERT INTO esrv_mailbox_smime_contacts (mailbox_id, email, cert_pem)
VALUES (?, ?, ?)
ON CONFLICT(mailbox_id, email) DO UPDATE SET cert_pem = excluded.cert_pem
`, mailboxID, email, certPEM)
return err
}
// GetSMIMEContact returns nil, nil if no certificate is on file for that email.
func (d *DB) GetSMIMEContact(mailboxID int64, email string) (*MailboxSMIMEContact, error) {
row := d.QueryRow(`SELECT id, mailbox_id, email, cert_pem, created_at FROM esrv_mailbox_smime_contacts WHERE mailbox_id = ? AND email = ?`, mailboxID, email)
var c MailboxSMIMEContact
if err := row.Scan(&c.ID, &c.MailboxID, &c.Email, &c.CertPEM, &c.CreatedAt); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
return nil, err
}
return &c, nil
}
// ListSMIMEContacts returns a mailbox's collected contact certificates, alphabetical
// by email.
func (d *DB) ListSMIMEContacts(mailboxID int64) ([]MailboxSMIMEContact, error) {
rows, err := d.Query(`SELECT id, mailbox_id, email, cert_pem, created_at FROM esrv_mailbox_smime_contacts WHERE mailbox_id = ? ORDER BY email`, mailboxID)
if err != nil {
return nil, err
}
defer rows.Close()
var out []MailboxSMIMEContact
for rows.Next() {
var c MailboxSMIMEContact
if err := rows.Scan(&c.ID, &c.MailboxID, &c.Email, &c.CertPEM, &c.CreatedAt); err != nil {
return nil, err
}
out = append(out, c)
}
return out, rows.Err()
}
// DeleteSMIMEContact removes one contact certificate, scoped to mailboxID so one
// mailbox owner can't delete another's contact by guessing its ID.
func (d *DB) DeleteSMIMEContact(mailboxID, contactID int64) error {
_, err := d.Exec(`DELETE FROM esrv_mailbox_smime_contacts WHERE mailbox_id = ? AND id = ?`, mailboxID, contactID)
return err
}