-
Notifications
You must be signed in to change notification settings - Fork 0
/
webauthn.go
135 lines (126 loc) · 3.72 KB
/
webauthn.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
130
131
132
133
134
135
package user
import (
"encoding/json"
cw "github.com/coscms/webauthn"
"github.com/go-webauthn/webauthn/webauthn"
"github.com/webx-top/com"
"github.com/webx-top/db"
"github.com/webx-top/echo"
"github.com/webx-top/echo/code"
"github.com/admpub/nging/v5/application/dbschema"
"github.com/admpub/nging/v5/application/handler"
"github.com/admpub/nging/v5/application/model"
"github.com/nging-plugins/webauthn/application/library/common"
)
var handle cw.UserHandler = &UserHandle{}
type UserHandle struct {
}
func (u *UserHandle) GetUser(ctx echo.Context, username string, opType cw.Type, stage cw.Stage) (webauthn.User, error) {
if opType == cw.TypeRegister || opType == cw.TypeUnbind {
user := handler.User(ctx)
if user == nil {
return nil, ctx.NewError(code.Unauthenticated, `请先登录`)
}
if username != user.Username {
return nil, ctx.NewError(code.NonPrivileged, `用户名不匹配`)
}
}
userM := model.NewUser(ctx)
err := userM.Get(func(r db.Result) db.Result {
return r.Select(`id`, `username`, `avatar`, `disabled`)
}, `username`, username)
if err != nil {
if err == db.ErrNoMoreRows {
err = ctx.NewError(code.UserNotFound, `用户不存在`).SetZone(`username`)
}
return nil, err
}
if userM.Disabled == `Y` {
err = ctx.NewError(code.UserDisabled, `该用户已被禁用`).SetZone(`disabled`)
return nil, err
}
user := &cw.User{
ID: uint64(userM.Id),
Name: userM.Username,
DisplayName: userM.Username,
Icon: userM.Avatar,
}
u2f := dbschema.NewNgingUserU2f(ctx)
_, err = u2f.ListByOffset(nil, nil, 0, -1, db.And(
db.Cond{`uid`: userM.Id},
db.Cond{`type`: `webauthn`},
db.Cond{`step`: 1},
))
if err != nil {
return nil, err
}
u2fList := u2f.Objects()
if opType == cw.TypeLogin && len(u2fList) == 0 {
err = ctx.NewError(code.Unsupported, `该用户不支持免密登录`)
return nil, err
}
user.Credentials = make([]webauthn.Credential, len(u2fList))
for index, row := range u2fList {
cred := webauthn.Credential{}
err = json.Unmarshal([]byte(row.Extra), &cred)
if err != nil {
return nil, err
}
user.Credentials[index] = cred
}
if opType == cw.TypeUnbind && stage == cw.StageBegin {
unbind := ctx.Form(`unbind`)
ctx.Session().Set(common.SessionKeyUnbindToken, unbind)
}
return user, nil
}
func (u *UserHandle) Register(ctx echo.Context, user webauthn.User, cred *webauthn.Credential) error {
userM := model.NewUser(ctx)
err := userM.Get(func(r db.Result) db.Result {
return r.Select(`id`, `disabled`)
}, `username`, user.WebAuthnName())
if err != nil {
return err
}
if userM.Disabled == `Y` {
err = ctx.NewError(code.UserDisabled, `该用户已被禁用`).SetZone(`disabled`)
return err
}
u2fM := model.NewUserU2F(ctx)
u2fM.Uid = userM.Id
u2fM.Token = com.ByteMd5(cred.ID)
u2fM.Name = common.GetOS(ctx.Request().UserAgent())
b, err := json.Marshal(cred)
if err != nil {
return err
}
u2fM.Extra = string(b)
u2fM.Type = `webauthn`
u2fM.Step = 1
_, err = u2fM.Add()
return err
}
func (u *UserHandle) Login(ctx echo.Context, user webauthn.User, cred *webauthn.Credential) error {
userM := model.NewUser(ctx)
err := userM.Get(nil, `username`, user.WebAuthnName())
if err != nil {
return err
}
err = userM.FireLoginSuccess(`webauthn`)
//userM.SetSession()
return err
}
func (u *UserHandle) Unbind(ctx echo.Context, user webauthn.User, cred *webauthn.Credential) error {
userM := model.NewUser(ctx)
err := userM.Get(nil, `username`, user.WebAuthnName())
if err != nil {
return err
}
u2fM := model.NewUserU2F(ctx)
unbind, _ := ctx.Session().Get(common.SessionKeyUnbindToken).(string)
err = u2fM.UnbindByToken(userM.Id, `webauthn`, 1, unbind)
if err == nil {
ctx.Session().Delete(common.SessionKeyUnbindToken)
}
return err
}