+106
appview/state/rbac.go
+106
appview/state/rbac.go
···
1
+
package state
2
+
3
+
import (
4
+
"database/sql"
5
+
"path"
6
+
7
+
sqladapter "github.com/Blank-Xu/sql-adapter"
8
+
"github.com/casbin/casbin/v2"
9
+
"github.com/casbin/casbin/v2/model"
10
+
)
11
+
12
+
const (
13
+
Model = `
14
+
[request_definition]
15
+
r = sub, dom, obj, act
16
+
17
+
[policy_definition]
18
+
p = sub, dom, obj, act
19
+
20
+
[role_definition]
21
+
g = _, _, _
22
+
23
+
[policy_effect]
24
+
e = some(where (p.eft == allow))
25
+
26
+
[matchers]
27
+
m = (r.act == p.act && r.dom == p.dom && keyMatch2(r.obj, p.obj) && g(r.sub, p.sub, r.dom))
28
+
`
29
+
)
30
+
31
+
type Enforcer struct {
32
+
E *casbin.SyncedEnforcer
33
+
domain string
34
+
}
35
+
36
+
func keyMatch2(key1 string, key2 string) bool {
37
+
matched, _ := path.Match(key2, key1)
38
+
return matched
39
+
}
40
+
41
+
func NewEnforcer(domain string) (*Enforcer, error) {
42
+
m, err := model.NewModelFromString(Model)
43
+
if err != nil {
44
+
return nil, err
45
+
}
46
+
47
+
// TODO: conf this
48
+
db, err := sql.Open("sqlite3", "appview.db")
49
+
if err != nil {
50
+
return nil, err
51
+
}
52
+
53
+
a, err := sqladapter.NewAdapter(db, "sqlite3", "acl")
54
+
if err != nil {
55
+
return nil, err
56
+
}
57
+
58
+
e, err := casbin.NewSyncedEnforcer(m, a)
59
+
if err != nil {
60
+
return nil, err
61
+
}
62
+
63
+
e.EnableAutoSave(true)
64
+
e.AddFunction("keyMatch2", keyMatch2Func)
65
+
66
+
// Add policies with patterns
67
+
_, err = e.AddPolicies([][]string{
68
+
{"server:owner", domain, domain, "server:invite"},
69
+
{"server:owner", domain, domain, "repo:create"},
70
+
{"server:owner", domain, domain, "repo:delete"}, // priveledged operation, delete any repo in domain
71
+
{"server:member", domain, domain, "repo:create"}, // priveledged operation, delete any repo in domain
72
+
})
73
+
if err != nil {
74
+
return nil, err
75
+
}
76
+
77
+
return &Enforcer{e, domain}, nil
78
+
}
79
+
80
+
func (e *Enforcer) AddOwner(owner string) error {
81
+
_, err := e.E.AddGroupingPolicy(owner, "server:owner", e.domain)
82
+
return err
83
+
}
84
+
85
+
func (e *Enforcer) AddMember(member string) error {
86
+
_, err := e.E.AddGroupingPolicy(member, "server:member", e.domain)
87
+
return err
88
+
}
89
+
90
+
func (e *Enforcer) AddRepo(member, domain, repo string) error {
91
+
_, err := e.E.AddPolicies([][]string{
92
+
{member, e.domain, repo, "repo:push"},
93
+
{member, e.domain, repo, "repo:owner"},
94
+
{member, e.domain, repo, "repo:invite"},
95
+
{member, e.domain, repo, "repo:delete"},
96
+
})
97
+
return err
98
+
}
99
+
100
+
// keyMatch2Func is a wrapper for keyMatch2 to make it compatible with Casbin
101
+
func keyMatch2Func(args ...interface{}) (interface{}, error) {
102
+
name1 := args[0].(string)
103
+
name2 := args[1].(string)
104
+
105
+
return keyMatch2(name1, name2), nil
106
+
}
+23
-4
appview/state/state.go
+23
-4
appview/state/state.go
···
21
21
)
22
22
23
23
type State struct {
24
-
db *db.DB
25
-
auth *auth.Auth
24
+
Db *db.DB
25
+
Auth *auth.Auth
26
26
}
27
27
28
28
func Make() (*State, error) {
···
36
36
return nil, err
37
37
}
38
38
39
-
return &State{db, auth}, nil
39
+
return &State{db, auth, nil}, nil
40
40
}
41
41
42
42
func (s *State) Login(w http.ResponseWriter, r *http.Request) {
···
223
223
w.Write([]byte("check success"))
224
224
225
225
// mark as registered
226
-
err = s.db.Register(domain)
226
+
err = s.Db.Register(domain)
227
+
if err != nil {
228
+
log.Println("failed to register domain", err)
229
+
http.Error(w, err.Error(), http.StatusInternalServerError)
230
+
}
231
+
232
+
// set permissions for this did as owner
233
+
_, did, err := s.Db.RegistrationStatus(domain)
227
234
if err != nil {
228
235
log.Println("failed to register domain", err)
236
+
http.Error(w, err.Error(), http.StatusInternalServerError)
237
+
}
238
+
239
+
e, err := NewEnforcer(domain)
240
+
if err != nil {
241
+
log.Println("failed to setup owner of domain", err)
242
+
http.Error(w, err.Error(), http.StatusInternalServerError)
243
+
}
244
+
245
+
err = e.AddOwner(did)
246
+
if err != nil {
247
+
log.Println("failed to setup owner of domain", err)
229
248
http.Error(w, err.Error(), http.StatusInternalServerError)
230
249
}
231
250
+4
go.mod
+4
go.mod
···
26
26
)
27
27
28
28
require (
29
+
github.com/Blank-Xu/sql-adapter v1.1.1 // indirect
29
30
github.com/Microsoft/go-winio v0.6.2 // indirect
30
31
github.com/ProtonMail/go-crypto v1.0.0 // indirect
31
32
github.com/acomagu/bufpipe v1.0.4 // indirect
32
33
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect
33
34
github.com/aymerick/douceur v0.2.0 // indirect
34
35
github.com/beorn7/perks v1.0.1 // indirect
36
+
github.com/bmatcuk/doublestar/v4 v4.7.1 // indirect
35
37
github.com/carlmjohnson/versioninfo v0.22.5 // indirect
38
+
github.com/casbin/casbin/v2 v2.103.0 // indirect
39
+
github.com/casbin/govaluate v1.3.0 // indirect
36
40
github.com/cespare/xxhash/v2 v2.2.0 // indirect
37
41
github.com/cloudflare/circl v1.4.0 // indirect
38
42
github.com/cyphar/filepath-securejoin v0.3.3 // indirect
+14
go.sum
+14
go.sum
···
1
+
github.com/Blank-Xu/sql-adapter v1.1.1 h1:+g7QXU9sl/qT6Po97teMpf3GjAO0X9aFaqgSePXvYko=
2
+
github.com/Blank-Xu/sql-adapter v1.1.1/go.mod h1:o2g8EZhZ3TudnYEGDkoU+3jCTCgDgx1o/Ig5ajKkaLY=
1
3
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
2
4
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
3
5
github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
···
26
28
github.com/bluekeyes/go-gitdiff v0.8.0/go.mod h1:WWAk1Mc6EgWarCrPFO+xeYlujPu98VuLW3Tu+B/85AE=
27
29
github.com/bluesky-social/indigo v0.0.0-20250123072624-9e3b84fdbb20 h1:yHusfYYi8odoCcsI6AurU+dRWb7itHAQNwt3/Rl9Vfs=
28
30
github.com/bluesky-social/indigo v0.0.0-20250123072624-9e3b84fdbb20/go.mod h1:Qp4YqWf+AQ3TwQCxV5Ls8O2tXE55zVTGVs3zTmn7BOg=
31
+
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
32
+
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
33
+
github.com/bmatcuk/doublestar/v4 v4.7.1 h1:fdDeAqgT47acgwd9bd9HxJRDmc9UAmPpc+2m0CXv75Q=
34
+
github.com/bmatcuk/doublestar/v4 v4.7.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
29
35
github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
30
36
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
31
37
github.com/carlmjohnson/versioninfo v0.22.5 h1:O00sjOLUAFxYQjlN/bzYTuZiS0y6fWDQjMRvwtKgwwc=
32
38
github.com/carlmjohnson/versioninfo v0.22.5/go.mod h1:QT9mph3wcVfISUKd0i9sZfVrPviHuSF+cUtLjm2WSf8=
39
+
github.com/casbin/casbin/v2 v2.100.0/go.mod h1:LO7YPez4dX3LgoTCqSQAleQDo0S0BeZBDxYnPUl95Ng=
40
+
github.com/casbin/casbin/v2 v2.103.0 h1:dHElatNXNrr8XcseUov0ZSiWjauwmZZE6YMV3eU1yic=
41
+
github.com/casbin/casbin/v2 v2.103.0/go.mod h1:Ee33aqGrmES+GNL17L0h9X28wXuo829wnNUnS0edAco=
42
+
github.com/casbin/govaluate v1.2.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
43
+
github.com/casbin/govaluate v1.3.0 h1:VA0eSY0M2lA86dYd5kPPuNZMUD9QkWnOCnavGrw9myc=
44
+
github.com/casbin/govaluate v1.3.0/go.mod h1:G/UnbIjZk/0uMNaLwZZmFQrR72tYRZWQkO70si/iR7A=
33
45
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
34
46
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
35
47
github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
···
74
86
github.com/go-yaml/yaml v2.1.0+incompatible/go.mod h1:w2MrLa16VYP0jy6N7M5kHaCkaLENm+P+Tv+MfurjSw0=
75
87
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
76
88
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
89
+
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
77
90
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
78
91
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
79
92
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
···
364
377
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
365
378
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
366
379
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
380
+
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
367
381
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
368
382
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
369
383
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=