tangled
alpha
login
or
join now
diffdown.com
/
diffdown-app
0
fork
atom
Diffdown is a real-time collaborative Markdown editor/previewer built on the AT Protocol
diffdown.com
0
fork
atom
overview
issues
10
pulls
pipelines
feat: add invite generation and validation
John Luther
3 weeks ago
984a4988
d6fae998
+73
2 changed files
expand all
collapse all
unified
split
internal
collaboration
invite.go
db
db.go
+54
internal/collaboration/invite.go
reviewed
···
1
1
+
package collaboration
2
2
+
3
3
+
import (
4
4
+
"crypto/rand"
5
5
+
"crypto/sha256"
6
6
+
"encoding/hex"
7
7
+
"fmt"
8
8
+
"time"
9
9
+
10
10
+
"github.com/limeleaf/diffdown/internal/db"
11
11
+
"github.com/limeleaf/diffdown/internal/model"
12
12
+
)
13
13
+
14
14
+
func GenerateInviteToken() (string, error) {
15
15
+
bytes := make([]byte, 32)
16
16
+
if _, err := rand.Read(bytes); err != nil {
17
17
+
return "", err
18
18
+
}
19
19
+
hash := sha256.Sum256(bytes)
20
20
+
return hex.EncodeToString(hash[:]), nil
21
21
+
}
22
22
+
23
23
+
func CreateInvite(database *db.DB, documentRKey, createdByDID string) (*model.Invite, error) {
24
24
+
token, err := GenerateInviteToken()
25
25
+
if err != nil {
26
26
+
return nil, err
27
27
+
}
28
28
+
29
29
+
invite := &model.Invite{
30
30
+
ID: db.NewID(),
31
31
+
DocumentRKey: documentRKey,
32
32
+
Token: token,
33
33
+
CreatedBy: createdByDID,
34
34
+
CreatedAt: time.Now(),
35
35
+
ExpiresAt: time.Now().Add(7 * 24 * time.Hour),
36
36
+
}
37
37
+
38
38
+
err = database.CreateInvite(invite)
39
39
+
return invite, err
40
40
+
}
41
41
+
42
42
+
func ValidateInvite(database *db.DB, token, documentRKey string) (*model.Invite, error) {
43
43
+
invite, err := database.GetInviteByToken(token)
44
44
+
if err != nil {
45
45
+
return nil, err
46
46
+
}
47
47
+
if invite.DocumentRKey != documentRKey {
48
48
+
return nil, fmt.Errorf("invite does not match document")
49
49
+
}
50
50
+
if time.Now().After(invite.ExpiresAt) {
51
51
+
return nil, fmt.Errorf("invite expired")
52
52
+
}
53
53
+
return invite, nil
54
54
+
}
+19
internal/db/db.go
reviewed
···
156
156
return err
157
157
}
158
158
159
159
+
// --- Invites ---
160
160
+
161
161
+
func (db *DB) CreateInvite(invite *model.Invite) error {
162
162
+
_, err := db.Exec(`
163
163
+
INSERT INTO invites (id, document_rkey, token, created_by_did, created_at, expires_at)
164
164
+
VALUES (?, ?, ?, ?, ?, ?)`,
165
165
+
invite.ID, invite.DocumentRKey, invite.Token, invite.CreatedBy, invite.CreatedAt, invite.ExpiresAt)
166
166
+
return err
167
167
+
}
168
168
+
169
169
+
func (db *DB) GetInviteByToken(token string) (*model.Invite, error) {
170
170
+
row := db.QueryRow(`SELECT id, document_rkey, token, created_by_did, created_at, expires_at FROM invites WHERE token = ?`, token)
171
171
+
var invite model.Invite
172
172
+
err := row.Scan(&invite.ID, &invite.DocumentRKey, &invite.Token, &invite.CreatedBy, &invite.CreatedAt, &invite.ExpiresAt)
173
173
+
if err != nil {
174
174
+
return nil, err
175
175
+
}
176
176
+
return &invite, nil
177
177
+
}