ref: master
accounts/subscriptions.go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
package accounts import ( "bytes" "crypto" "crypto/ed25519" "encoding/base64" "errors" "fmt" "time" "git.sr.ht/~sircmpwn/go-bare" "github.com/google/uuid" ) type Seat string func ParseSeat(s string) (Seat, error) { switch s { case string(SEAT_BACK): return SEAT_BACK, nil case string(SEAT_WINDOW): return SEAT_WINDOW, nil case string(SEAT_FRONT): return SEAT_FRONT, nil case string(SEAT_DRIVER): return SEAT_DRIVER, nil case string(SEAT_PILOT): return SEAT_PILOT, nil case string(SEAT_GARAGE): return SEAT_GARAGE, nil default: return SEAT_BACK, errors.New("No such seat: " + s) } } func (s Seat) String() string { return string(s) } const ( SEAT_BACK Seat = "back" SEAT_WINDOW Seat = "window" SEAT_FRONT Seat = "front" SEAT_DRIVER Seat = "driver" SEAT_PILOT Seat = "pilot" SEAT_GARAGE Seat = "garage" ) type Subscription struct { ID string Plan Seat ValidSince time.Time Validity int // months Creator string // user ID Signature []byte // TODO payment ID } type SubscriptionTicket struct { ID string Plan string Validity int // months Creator string // user ID Signature []byte } func (s SubscriptionTicket) Marshal() ([]byte, error) { bytes, err := bare.Marshal(&s) return bytes, err } func ParseSubscription(s string) (SubscriptionTicket, error) { t := SubscriptionTicket{} bytes, err := base64.StdEncoding.DecodeString(s) if err != nil { return SubscriptionTicket{}, fmt.Errorf("while decoding base64: %w", err) } err = bare.Unmarshal(bytes, &t) if err != nil { return t, fmt.Errorf("while unmarshalling: %w", err) } return t, nil } func CreateSubscription(plan Seat, validity int, keySeed []byte) error { subscription := SubscriptionTicket{ ID: uuid.NewString(), Plan: plan.String(), Validity: validity, Creator: "cli", } signed, err := subscription.Marshal() if err != nil { return fmt.Errorf("while marshalling signed subscription: %w", err) } fmt.Println(base64.StdEncoding.EncodeToString(signed)) return nil } func sign(subscription SubscriptionTicket, keySeed []byte) (SubscriptionTicket, error) { privateKey := ed25519.NewKeyFromSeed(keySeed) unsigned, err := subscription.Marshal() if err != nil { return subscription, fmt.Errorf("while marshalling unsigned subscription: %w", err) } signature, err := privateKey.Sign(nil, unsigned, crypto.Hash(0)) if err != nil { return subscription, fmt.Errorf("while signing subscription: %w", err) } subscription.Signature = signature return subscription, nil } func CheckSignature(s SubscriptionTicket, keySeed []byte) (bool, error) { signature := s.Signature s.Signature = []byte{} signed, err := sign(s, keySeed) if err != nil { return false, err } return bytes.Compare(signature, signed.Signature) == 0, nil } |