auth
auth/token_postgres.go
Implement an endpoint for token information. Implement an endpoint that allows us to look up information on a token. We strip the refresh token before the response is sent to avoid leaking the response token.
1 package auth
3 import (
4 "code.secondbit.org/uuid.hg"
6 "github.com/lib/pq"
7 "github.com/secondbit/pan"
8 )
10 func (t Token) GetSQLTableName() string {
11 return "tokens"
12 }
14 func (p *postgres) getTokenSQL(token string, refresh bool) *pan.Query {
15 var t Token
16 fields, _ := pan.GetFields(t)
17 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(t))
18 query.IncludeWhere()
19 if !refresh {
20 query.Include(pan.GetUnquotedColumn(t, "AccessToken")+" = ?", token)
21 } else {
22 query.Include(pan.GetUnquotedColumn(t, "RefreshToken")+" = ?", token)
23 }
24 return query.FlushExpressions(" ")
25 }
27 func (p *postgres) getToken(token string, refresh bool) (Token, error) {
28 query := p.getTokenSQL(token, refresh)
29 rows, err := p.db.Query(query.String(), query.Args...)
30 if err != nil {
31 return Token{}, err
32 }
33 var t Token
34 var found bool
35 for rows.Next() {
36 err := pan.Unmarshal(rows, &t)
37 if err != nil {
38 return t, err
39 }
40 found = true
41 }
42 if err = rows.Err(); err != nil {
43 return t, err
44 }
45 if !found {
46 return t, ErrTokenNotFound
47 }
48 return t, nil
49 }
51 func (p *postgres) saveTokenSQL(token Token) *pan.Query {
52 fields, values := pan.GetFields(token)
53 query := pan.New(pan.POSTGRES, "INSERT INTO "+pan.GetTableName(token))
54 query.Include("(" + pan.QueryList(fields) + ")")
55 query.Include("VALUES")
56 query.Include("("+pan.VariableList(len(values))+")", values...)
57 return query.FlushExpressions(" ")
58 }
60 func (p *postgres) saveToken(token Token) error {
61 query := p.saveTokenSQL(token)
62 _, err := p.db.Exec(query.String(), query.Args...)
63 if e, ok := err.(*pq.Error); ok && e.Constraint == "tokens_pkey" {
64 err = ErrTokenAlreadyExists
65 }
66 if err != nil || len(token.Scopes) < 1 {
67 return err
68 }
69 return err
70 }
72 func (p *postgres) revokeTokenSQL(token string, refresh bool) *pan.Query {
73 var t Token
74 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(t)+" SET ")
75 query.Include(pan.GetUnquotedColumn(t, "Revoked")+" = ?", true)
76 query.IncludeWhere()
77 if !refresh {
78 query.Include(pan.GetUnquotedColumn(t, "AccessToken")+" = ?", token)
79 } else {
80 query.Include(pan.GetUnquotedColumn(t, "RefreshToken")+" = ?", token)
81 }
82 return query.FlushExpressions(" ")
83 }
85 func (p *postgres) revokeToken(token string, refresh bool) error {
86 query := p.revokeTokenSQL(token, refresh)
87 res, err := p.db.Exec(query.String(), query.Args...)
88 if err != nil {
89 return err
90 }
91 rows, err := res.RowsAffected()
92 if err != nil {
93 return err
94 }
95 if rows == 0 {
96 return ErrTokenNotFound
97 }
98 return nil
99 }
101 func (p *postgres) revokeTokensByProfileIDSQL(profileID uuid.ID) *pan.Query {
102 var t Token
103 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(t)+" SET ")
104 query.Include(pan.GetUnquotedColumn(t, "Revoked")+" = ?", true)
105 query.IncludeWhere()
106 query.Include(pan.GetUnquotedColumn(t, "ProfileID")+" = ?", profileID)
107 return query.FlushExpressions(" ")
108 }
110 func (p *postgres) revokeTokensByProfileID(profileID uuid.ID) error {
111 query := p.revokeTokensByProfileIDSQL(profileID)
112 res, err := p.db.Exec(query.String(), query.Args...)
113 if err != nil {
114 return err
115 }
116 rows, err := res.RowsAffected()
117 if err != nil {
118 return err
119 }
120 if rows == 0 {
121 return ErrProfileNotFound
122 }
123 return nil
124 }
126 func (p *postgres) revokeTokensByClientIDSQL(clientID uuid.ID) *pan.Query {
127 var t Token
128 query := pan.New(pan.POSTGRES, "UPDATE "+pan.GetTableName(t)+" SET ")
129 query.Include(pan.GetUnquotedColumn(t, "Revoked")+" = ?", true)
130 query.IncludeWhere()
131 query.Include(pan.GetUnquotedColumn(t, "ClientID")+" = ?", clientID)
132 return query.FlushExpressions(" ")
133 }
135 func (p *postgres) revokeTokensByClientID(clientID uuid.ID) error {
136 query := p.revokeTokensByClientIDSQL(clientID)
137 res, err := p.db.Exec(query.String(), query.Args...)
138 if err != nil {
139 return err
140 }
141 rows, err := res.RowsAffected()
142 if err != nil {
143 return err
144 }
145 if rows == 0 {
146 return ErrClientNotFound
147 }
148 return nil
149 }
151 func (p *postgres) getTokensByProfileIDSQL(profileID uuid.ID, num, offset int) *pan.Query {
152 var token Token
153 fields, _ := pan.GetFields(token)
154 query := pan.New(pan.POSTGRES, "SELECT "+pan.QueryList(fields)+" FROM "+pan.GetTableName(token))
155 query.IncludeWhere()
156 query.Include(pan.GetUnquotedColumn(token, "ProfileID")+" = ?", profileID)
157 query.IncludeLimit(int64(num))
158 query.IncludeOffset(int64(offset))
159 return query.FlushExpressions(" ")
160 }
162 func (p *postgres) getTokensByProfileID(profileID uuid.ID, num, offset int) ([]Token, error) {
163 query := p.getTokensByProfileIDSQL(profileID, num, offset)
164 rows, err := p.db.Query(query.String(), query.Args...)
165 if err != nil {
166 return []Token{}, err
167 }
168 var tokens []Token
169 var tokenIDs []string
170 for rows.Next() {
171 var token Token
172 err = pan.Unmarshal(rows, &token)
173 if err != nil {
174 return tokens, err
175 }
176 tokens = append(tokens, token)
177 tokenIDs = append(tokenIDs, token.AccessToken)
178 }
179 if err = rows.Err(); err != nil {
180 return tokens, err
181 }
182 return tokens, nil
183 }