| 1 | package calendar |
| 2 | |
| 3 | import ( |
| 4 | "encoding/base64" |
| 5 | "errors" |
| 6 | "fmt" |
| 7 | |
| 8 | "amadan.net/oficina/calendar/internal/calendar/seal" |
| 9 | "gorm.io/gorm" |
| 10 | ) |
| 11 | |
| 12 | const keyCheckMeta = "sealed_key_check_v1" |
| 13 | const keyCheckPurpose = "key.check.v1" |
| 14 | const keyCheckValue = "oficina/calendar key check v1" |
| 15 | |
| 16 | func checkDataKey(g *gorm.DB, sealer *seal.Sealer) error { |
| 17 | return g.Transaction(func(tx *gorm.DB) error { |
| 18 | var row Meta |
| 19 | err := tx.Where("key = ?", keyCheckMeta).First(&row).Error |
| 20 | if err == nil { |
| 21 | sealed, err := base64.StdEncoding.DecodeString(row.Value) |
| 22 | if err != nil { |
| 23 | return errors.New("calendar: invalid data key check") |
| 24 | } |
| 25 | plain, err := sealer.OpenString(keyCheckPurpose, sealed) |
| 26 | if err != nil || plain != keyCheckValue { |
| 27 | return errors.New("calendar: data key does not match database") |
| 28 | } |
| 29 | return nil |
| 30 | } |
| 31 | if !errors.Is(err, gorm.ErrRecordNotFound) { |
| 32 | return err |
| 33 | } |
| 34 | var calendars []Calendar |
| 35 | if err := tx.Find(&calendars).Error; err != nil { |
| 36 | return err |
| 37 | } |
| 38 | for _, c := range calendars { |
| 39 | if _, err := sealer.OpenString(seal.PurposeCalendarName, c.NameSealed); err != nil { |
| 40 | return fmt.Errorf("calendar: data key cannot open existing calendar: %w", err) |
| 41 | } |
| 42 | } |
| 43 | sealed, err := sealer.SealString(keyCheckPurpose, keyCheckValue) |
| 44 | if err != nil { |
| 45 | return err |
| 46 | } |
| 47 | return tx.Create(&Meta{Key: keyCheckMeta, Value: base64.StdEncoding.EncodeToString(sealed)}).Error |
| 48 | }) |
| 49 | } |
| 50 | |