diff --git a/backend/api/base.go b/backend/api/base.go new file mode 100644 index 0000000..0789ea0 --- /dev/null +++ b/backend/api/base.go @@ -0,0 +1,37 @@ +package api + +import ( + "encoding/json" + "io" +) + +const ( + codeError = -1 + codeSuccess = 0 + codeTimeout = 401 +) + +const ( + typeSuccess = "success" + typeError = "error" +) + +const ( + messageOk = "ok" +) + +type base struct { + Code int `json:"code"` + Message string `json:"message"` + Result any `json:"result"` + Type string `json:"type"` +} + +func writeresult(w io.Writer, c int, r any, m, t string) error { + return json.NewEncoder(w).Encode(&base{ + Code: c, + Result: r, + Message: m, + Type: t, + }) +} diff --git a/backend/api/login.go b/backend/api/login.go new file mode 100644 index 0000000..60cb6a6 --- /dev/null +++ b/backend/api/login.go @@ -0,0 +1,142 @@ +package api + +import ( + "crypto/md5" + crand "crypto/rand" + "encoding/base64" + "encoding/hex" + "errors" + "math/rand" + "sync/atomic" + "time" + + "github.com/FloatTech/ttl" + "github.com/RomiChan/syncx" + base14 "github.com/fumiama/go-base16384" + + "github.com/fumiama/paper-manager/backend/global" +) + +var ( + errNoSuchUser = errors.New("invalid username or password") + errTooManySalts = errors.New("too many salts") + errInvalidLoginStatus = errors.New("invalid login status") + errEmptySalt = errors.New("empty salt") + errWrongPassword = errors.New("invalid username or password") + errTooManyFailedLogins = errors.New("too many failed logins") +) + +const ( + loginStatusYes = iota - 1 + loginStatusNo + loginStatusFail1 + loginStatusFail2 + loginStatusFail3 + loginStatusFailLast +) + +const maxSaltCount = 4 + +type saltinfo struct { + Salt string `json:"salt"` + count *uintptr +} + +var ( + loginsalts = ttl.NewCache[string, saltinfo](time.Minute) + loginstatus = syncx.Map[string, int]{} +) + +func getLoginSalt(username string) (*saltinfo, error) { + if !global.UserDB.IsNameExists(username) { + return nil, errNoSuchUser + } + s, _ := loginstatus.Load(username) + if s != loginStatusNo { + return nil, errInvalidLoginStatus + } + salt := loginsalts.Get(username) + if salt.count != nil { + if atomic.AddUintptr(salt.count, 1) >= maxSaltCount { + time.AfterFunc(time.Minute*2, func() { atomic.StoreUintptr(salt.count, 0) }) + return nil, errTooManySalts + } + if salt.Salt != "" { + return &salt, nil + } + } + buf := make([]byte, 7*(rand.Intn(8)+1)) + _, err := crand.Read(buf) + if err != nil { + return nil, err + } + salt.Salt = base14.EncodeToString(buf) + salt.count = new(uintptr) + loginsalts.Set(username, salt) + return &salt, nil +} + +type role struct { + RoleName string `json:"roleName"` + Value string `json:"value"` +} + +type loginResult struct { + Roles []role `json:"roles"` + UserID int `json:"userId"` + Username string `json:"username"` + Token string `json:"token"` + RealName string `json:"realName"` + Desc string `json:"desc"` +} + +var ( + usertokens = ttl.NewCache[string, *global.User](time.Hour) +) + +func login(username, challenge string) (*loginResult, error) { + if !global.UserDB.IsNameExists(username) { + return nil, errNoSuchUser + } + s, loaded := loginstatus.LoadOrStore(username, loginStatusFail1) + if loaded { + if s == loginStatusYes { + return nil, errInvalidLoginStatus + } + if s >= loginStatusFailLast { + return nil, errTooManyFailedLogins + } + loginstatus.Store(username, s+1) + } + salt := loginsalts.Get(username) + if salt.count == nil || salt.Salt == "" { + return nil, errEmptySalt + } + user, err := global.UserDB.GetUserByName(username) + if err != nil { + return nil, err + } + h := md5.New() + h.Write(base14.StringToBytes(user.Pswd)) + h.Write(base14.StringToBytes(salt.Salt)) + passchlg := hex.EncodeToString(h.Sum(make([]byte, 0, md5.Size))) + if passchlg != challenge { + return nil, errWrongPassword + } + var buf [6 * 8]byte + _, err = crand.Read(buf[:]) + if err != nil { + return nil, err + } + token := base64.RawStdEncoding.EncodeToString(buf[:]) + usertokens.Set(token, &user) + loginstatus.Store(username, loginStatusYes) + return &loginResult{ + Roles: []role{{RoleName: user.Role.Nick(), Value: user.Role.String()}}, + UserID: *user.ID, + Username: user.Name, + Token: token, + RealName: user.Nick, + Desc: user.Desc, + }, nil +} diff --git a/backend/api/main.go b/backend/api/main.go index c023f95..d63ad57 100644 --- a/backend/api/main.go +++ b/backend/api/main.go @@ -1,6 +1,7 @@ package api import ( + "encoding/json" "net/http" "github.com/fumiama/paper-manager/backend/utils" @@ -8,8 +9,62 @@ import ( // Handler serves all backend /api call func Handler(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/api/getLoginSalt" { + if !utils.IsMethod("GET", w, r) { + return + } + username := r.URL.Query().Get("username") + if username == "" { + http.Error(w, "400 Bad Request: empty username", http.StatusBadRequest) + return + } + salt, err := getLoginSalt(username) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + writeresult(w, codeSuccess, salt, messageOk, typeSuccess) + return + } + if r.URL.Path == "/api/login" { + if !utils.IsMethod("POST", w, r) { + return + } + defer r.Body.Close() + var body loginbody + err := json.NewDecoder(r.Body).Decode(&body) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + r, err := login(body.Username, body.Password) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + writeresult(w, codeSuccess, r, messageOk, typeSuccess) + return + } + if r.URL.Path == "/api/getUserInfo" { + if !utils.IsMethod("GET", w, r) { + return + } + token := r.Header.Get("Authorization") + r, err := getUserInfo(token) + if err != nil { + writeresult(w, codeError, nil, err.Error(), typeError) + return + } + writeresult(w, codeSuccess, r, messageOk, typeSuccess) + return + } if !utils.IsMethod("GET", w, r) { return } http.Error(w, "404 Not Found", http.StatusNotFound) } + +type loginbody struct { + Username string `json:"username"` + Password string `json:"password"` +} diff --git a/backend/api/user.go b/backend/api/user.go new file mode 100644 index 0000000..29edbe1 --- /dev/null +++ b/backend/api/user.go @@ -0,0 +1,42 @@ +package api + +import ( + "errors" + + "github.com/fumiama/paper-manager/backend/global" +) + +var ( + errInvalidToken = errors.New("invalid token") +) + +type getUserInfoResult struct { + UserID int `json:"userId"` + Username string `json:"username"` + RealName string `json:"realName"` + Avatar string `json:"avatar"` + Desc string `json:"desc"` + HomePath string `json:"homePath"` + Roles []role `json:"roles"` +} + +func getUserInfo(token string) (*getUserInfoResult, error) { + user := usertokens.Get(token) + if user == nil { + return nil, errInvalidToken + } + return &getUserInfoResult{ + UserID: *user.ID, + Username: user.Name, + RealName: user.Nick, + Avatar: user.Avtr, + Desc: user.Desc, + HomePath: func() string { + if user.Role == global.RoleSuper { + return "/dashboard/analysis" + } + return "/dashboard/workbench" + }(), + Roles: []role{{RoleName: user.Role.Nick(), Value: user.Role.String()}}, + }, nil +} diff --git a/backend/global/db.go b/backend/global/db.go new file mode 100644 index 0000000..5119a3e --- /dev/null +++ b/backend/global/db.go @@ -0,0 +1,26 @@ +package global + +import ( + "sync" + + sql "github.com/FloatTech/sqlite" +) + +const ( + userdbpath = DataFolder + "user.db" + filedbpath = DataFolder + "file.db" +) + +type UserDatabase struct { + mu sync.RWMutex + db sql.Sqlite +} +type FileDatabase struct { + mu sync.RWMutex + db sql.Sqlite +} + +var ( + UserDB = UserDatabase{db: sql.Sqlite{DBPath: userdbpath}} + FileDB = FileDatabase{db: sql.Sqlite{DBPath: filedbpath}} +) diff --git a/backend/global/file.go b/backend/global/file.go new file mode 100644 index 0000000..5d67a37 --- /dev/null +++ b/backend/global/file.go @@ -0,0 +1,16 @@ +package global + +import "time" + +func init() { + err := FileDB.db.Open(time.Hour) + if err != nil { + panic(err) + } +} + +type File struct { + ID *int +} + +func (f *FileDatabase) AddFile() {} diff --git a/backend/global/user.go b/backend/global/user.go new file mode 100644 index 0000000..be4e66f --- /dev/null +++ b/backend/global/user.go @@ -0,0 +1,440 @@ +package global + +import ( + "errors" + "strconv" + "strings" + "time" + + "github.com/fumiama/paper-manager/backend/utils" + "github.com/sirupsen/logrus" +) + +const ( + RoleNil UserRole = iota + RoleSuper + RoleFileManager + RoleUser +) + +type UserRole uint8 + +func (r UserRole) String() string { + switch r { + case RoleSuper: + return "super" + case RoleFileManager: + return "filemgr" + case RoleUser: + return "user" + } + return "nil" +} + +func (r UserRole) Nick() string { + switch r { + case RoleSuper: + return "课程组长" + case RoleFileManager: + return "归档代理" + case RoleUser: + return "课程组员" + } + return "nil" +} + +const ( + UserTableUser = "user" + UserTableMessage = "msg" +) + +var ( + ErrInvalidRole = errors.New("invalid role") + ErrEmptyPassword = errors.New("empty password") + ErrEmptyName = errors.New("empty name") + ErrInvalidUsersCount = errors.New("invalid users count") + ErrEmptyUserID = errors.New("empty user ID") + ErrEmptyContect = errors.New("empty contact") + ErrUsernameExists = errors.New("username exists") +) + +func init() { + isinit := utils.IsNotExist(UserDB.db.DBPath) + err := UserDB.db.Open(time.Hour) + if err != nil { + panic(err) + } + _, err = UserDB.db.DB.Exec("PRAGMA foreign_keys = ON;") + if err != nil { + panic(err) + } + err = UserDB.db.Create(UserTableUser, &User{}) + if err != nil { + panic(err) + } + err = UserDB.db.Create(UserTableMessage, &Message{}, + "FOREIGN KEY(ToID) REFERENCES "+UserTableUser+"(ID)", + ) + if err != nil { + panic(err) + } + if isinit { // 添加初始账户 + UserDB.AddUser(&User{ + Role: RoleSuper, + Pswd: "123456", + Name: "fumiama", + Nick: "源文雨", + Avtr: "https://q1.qlogo.cn/g?b=qq&nk=1332524221&s=640", + Cont: "028-61830156", + Desc: "日は山の端にかかりぬ", + }, "系统") + logrus.Warn("[global.user] 初次启动, 创建初始账户 fumiama 密码 123456") + } +} + +// User stores a user in table named UserTableUser +type User struct { + ID *int + Role UserRole + Date int64 // Date is the creating date's unix timestamp + Pswd string + Last int64 // Last is the last password reseting unix timestamp + Name string + Nick string + Avtr string // Avtr is the user's avatar, typically a image url + Cont string // Cont is the user's contact, ex. phone number + Desc string +} + +// AddUser but cannot customize the ID field for it is self-increasing +func (u *UserDatabase) AddUser(user *User, opname string) error { + user.ID = nil + if user.Role == RoleNil || user.Role > RoleUser { + return ErrInvalidRole + } + if user.Pswd == "" { + return ErrEmptyPassword + } + if user.Name == "" { + return ErrEmptyName + } + if u.IsNameExists(user.Name) { + return ErrUsernameExists + } + user.Date = time.Now().Unix() + user.Last = user.Date + _ = u.notifyUserAdded(opname, user.Name) + u.mu.Lock() + defer u.mu.Unlock() + return u.db.InsertUnique(UserTableUser, user) +} + +// UpdateUserInfo ... +func (u *UserDatabase) UpdateUserInfo(id int, nick, avtr, desc string) error { + user, err := u.GetUserByID(id) + if err != nil { + return err + } + if nick != "" { + user.Nick = nick + } + if avtr != "" { + user.Avtr = avtr + } + if desc != "" { + user.Desc = desc + } + u.mu.Lock() + defer u.mu.Unlock() + return u.db.Insert(UserTableUser, user) +} + +// UpdateUserRole ... +func (u *UserDatabase) UpdateUserRole(id int, nr UserRole) error { + if nr == RoleNil || nr > RoleUser { + return ErrInvalidRole + } + user, err := u.GetUserByID(id) + if err != nil { + return err + } + user.Role = nr + u.mu.Lock() + defer u.mu.Unlock() + return u.db.Insert(UserTableUser, user) +} + +// UpdateUserPassword ... +func (u *UserDatabase) UpdateUserPassword(id int, npwd string) error { + if npwd == "" { + return ErrEmptyPassword + } + user, err := u.GetUserByID(id) + if err != nil { + return err + } + user.Last = time.Now().Unix() + user.Pswd = npwd + _ = u.notifyPasswordChange(user.Name, npwd) + u.mu.Lock() + defer u.mu.Unlock() + return u.db.Insert(UserTableUser, user) +} + +// UpdateUserContact ... +func (u *UserDatabase) UpdateUserContact(id int, ncont string) error { + if ncont == "" { + return ErrEmptyContect + } + user, err := u.GetUserByID(id) + if err != nil { + return err + } + user.Cont = ncont + _ = u.notifyContactChange(user.Name, ncont) + u.mu.Lock() + defer u.mu.Unlock() + return u.db.Insert(UserTableUser, user) +} + +// GetUserByName avoids sql injection by removing ; ' " = +func (u *UserDatabase) GetUserByName(username string) (user User, err error) { + username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username) + u.mu.RLock() + err = u.db.Find(UserTableUser, &user, "WHERE Name='"+username+"'") + u.mu.RUnlock() + return +} + +// IsNameExists avoids sql injection by removing ; ' " = +func (u *UserDatabase) IsNameExists(username string) bool { + username = strings.NewReplacer(";", "", "'", "", `"`, "", "=", "").Replace(username) + u.mu.RLock() + defer u.mu.RUnlock() + return u.db.CanFind(UserTableUser, "WHERE Name='"+username+"'") +} + +// GetUserByID ... +func (u *UserDatabase) GetUserByID(id int) (user User, err error) { + u.mu.RLock() + err = u.db.Find(UserTableUser, &user, "WHERE ID="+strconv.Itoa(id)) + u.mu.RUnlock() + return +} + +// DelUserByID ... +func (u *UserDatabase) DelUserByID(id int) (err error) { + u.mu.Lock() + err = u.db.Del(UserTableUser, "WHERE ID="+strconv.Itoa(id)) + u.mu.Unlock() + return +} + +// GetUsers will set Pswd field to empty +func (u *UserDatabase) GetUsers() (users []User, err error) { + var user User + u.mu.RLock() + defer u.mu.RUnlock() + n, err := u.db.Count(UserTableUser) + if err != nil { + return + } + users = make([]User, n) + i := 0 + err = u.db.FindFor(UserTableUser, &user, "", func() error { + user.Pswd = "" + users[i] = user + i++ + if i >= n { + return ErrInvalidUsersCount + } + return nil + }) + return +} + +func (u *UserDatabase) GetSuperIDs() (ids []int, err error) { + var user User + ids = make([]int, 0, 16) + u.mu.RLock() + defer u.mu.RUnlock() + err = u.db.FindFor(UserTableUser, &user, "WHERE Role="+strconv.Itoa(int(RoleSuper)), func() error { + ids = append(ids, *user.ID) + return nil + }) + return +} + +// Message is shown in the workbench +type Message struct { + ID *int + ToID int // ToID user's ID + Date int64 + Text string // Text is the message content + Name string // Name is the user's name to add in register message + Cont string // Cont is the user's phone number to add in register message or an operator's name in add user message + Pswd string // Pswd is the user's password to add in register message +} + +// SendMessage will send a message +func (u *UserDatabase) SendMessage(m *Message) error { + m.ID = nil + m.Date = time.Now().Unix() + u.mu.Lock() + defer u.mu.Unlock() + return u.db.InsertUnique(UserTableMessage, &m) +} + +// NotifyRegister will send register notification to all supers +func (u *UserDatabase) NotifyRegister(name, cont, pswd string) error { + if name == "" { + return ErrEmptyName + } + if pswd == "" { + return ErrEmptyPassword + } + + tos, err := u.GetSuperIDs() + if err != nil { + return err + } + + m := Message{ + Date: time.Now().Unix(), + Text: "收到来自 " + name + " 的注册请求, 联系方式: " + cont, + Name: name, + Cont: cont, + Pswd: pswd, + } + u.mu.Lock() + defer u.mu.Unlock() + for _, to := range tos { + m.ToID = to + err = u.db.InsertUnique(UserTableMessage, &m) + if err != nil { + return err + } + } + return nil +} + +// notifyUserAdded will send notification to all supers +func (u *UserDatabase) notifyUserAdded(opname, name string) error { + if opname == "" || name == "" { + return ErrEmptyName + } + + tos, err := u.GetSuperIDs() + if err != nil { + return err + } + + m := Message{ + Date: time.Now().Unix(), + Text: opname + "添加了用户 " + name, + Name: name, + Cont: opname, + } + u.mu.Lock() + defer u.mu.Unlock() + for _, to := range tos { + m.ToID = to + err = u.db.InsertUnique(UserTableMessage, &m) + if err != nil { + return err + } + } + return nil +} + +// notifyContactChange will send notification to all supers +func (u *UserDatabase) notifyContactChange(name, cont string) error { + if name == "" { + return ErrEmptyName + } + + tos, err := u.GetSuperIDs() + if err != nil { + return err + } + + m := Message{ + Date: time.Now().Unix(), + Text: "用户 " + name + " 更改联系方式为: " + cont, + Name: name, + Cont: cont, + } + u.mu.Lock() + defer u.mu.Unlock() + for _, to := range tos { + m.ToID = to + err = u.db.InsertUnique(UserTableMessage, &m) + if err != nil { + return err + } + } + return nil +} + +// notifyPasswordChange will send notification to all supers +func (u *UserDatabase) notifyPasswordChange(name, npwd string) error { + if name == "" { + return ErrEmptyName + } + + tos, err := u.GetSuperIDs() + if err != nil { + return err + } + + m := Message{ + Date: time.Now().Unix(), + Text: "用户 " + name + " 更改了密码", + Name: name, + Pswd: npwd, + } + u.mu.Lock() + defer u.mu.Unlock() + for _, to := range tos { + m.ToID = to + err = u.db.InsertUnique(UserTableMessage, &m) + if err != nil { + return err + } + } + return nil +} + +// GetMessagesOfUser set Pswd field to empty +func (u *UserDatabase) GetMessagesOfUser(to int) (ms []Message, err error) { + u.mu.RLock() + defer u.mu.RUnlock() + n, err := u.db.Count(UserTableMessage) + if err != nil { + return + } + ms = make([]Message, 0, n) + m := Message{} + err = u.db.FindFor(UserTableMessage, &m, "WHERE ToID="+strconv.Itoa(to), func() error { + m.Pswd = "" + ms = append(ms, m) + return nil + }) + return +} + +// GetMessageByID ... +func (u *UserDatabase) GetMessageByID(id int) (m Message, err error) { + u.mu.RLock() + err = u.db.Find(UserTableMessage, &m, "WHERE ID="+strconv.Itoa(id)) + u.mu.RUnlock() + return +} + +// DelMessageByID ... +func (u *UserDatabase) DelMessageByID(id int) (err error) { + u.mu.Lock() + err = u.db.Del(UserTableMessage, "WHERE ID="+strconv.Itoa(id)) + u.mu.Unlock() + return +} diff --git a/backend/utils/file.go b/backend/utils/file.go new file mode 100644 index 0000000..3bd9e08 --- /dev/null +++ b/backend/utils/file.go @@ -0,0 +1,25 @@ +package utils + +import "os" + +// IsExist 文件/路径存在 +func IsExist(path string) bool { + _, err := os.Stat(path) + return err == nil || os.IsExist(err) +} + +// IsNotExist 文件/路径不存在 +func IsNotExist(path string) bool { + _, err := os.Stat(path) + return err != nil && os.IsNotExist(err) +} + +// FileSize 获取文件大小 +func FileSize(path string) (n int64) { + stat, err := os.Stat(path) + if err != nil { + return + } + n = stat.Size() + return +} diff --git a/frontend/vben/mock/sys/menu.ts b/frontend/vben/mock/sys/menu.ts deleted file mode 100644 index 21d0cb0..0000000 --- a/frontend/vben/mock/sys/menu.ts +++ /dev/null @@ -1,260 +0,0 @@ -import { resultSuccess, resultError, getRequestToken, requestParams } from '../_util' -import { MockMethod } from 'vite-plugin-mock' -import { createFakeUserList } from './user' - -// single -const dashboardRoute = { - path: '/dashboard', - name: 'Dashboard', - component: 'LAYOUT', - redirect: '/dashboard/analysis', - meta: { - title: 'routes.dashboard.dashboard', - hideChildrenInMenu: true, - icon: 'bx:bx-home', - }, - children: [ - { - path: 'analysis', - name: 'Analysis', - component: '/dashboard/analysis/index', - meta: { - hideMenu: true, - hideBreadcrumb: true, - title: 'routes.dashboard.analysis', - currentActiveMenu: '/dashboard', - icon: 'bx:bx-home', - }, - }, - { - path: 'workbench', - name: 'Workbench', - component: '/dashboard/workbench/index', - meta: { - hideMenu: true, - hideBreadcrumb: true, - title: 'routes.dashboard.workbench', - currentActiveMenu: '/dashboard', - icon: 'bx:bx-home', - }, - }, - ], -} - -const backRoute = { - path: 'back', - name: 'PermissionBackDemo', - meta: { - title: 'routes.demo.permission.back', - }, - - children: [ - { - path: 'page', - name: 'BackAuthPage', - component: '/demo/permission/back/index', - meta: { - title: 'routes.demo.permission.backPage', - }, - }, - { - path: 'btn', - name: 'BackAuthBtn', - component: '/demo/permission/back/Btn', - meta: { - title: 'routes.demo.permission.backBtn', - }, - }, - ], -} - -const authRoute = { - path: '/permission', - name: 'Permission', - component: 'LAYOUT', - redirect: '/permission/front/page', - meta: { - icon: 'carbon:user-role', - title: 'routes.demo.permission.permission', - }, - children: [backRoute], -} - -const levelRoute = { - path: '/level', - name: 'Level', - component: 'LAYOUT', - redirect: '/level/menu1/menu1-1', - meta: { - icon: 'carbon:user-role', - title: 'routes.demo.level.level', - }, - - children: [ - { - path: 'menu1', - name: 'Menu1Demo', - meta: { - title: 'Menu1', - }, - children: [ - { - path: 'menu1-1', - name: 'Menu11Demo', - meta: { - title: 'Menu1-1', - }, - children: [ - { - path: 'menu1-1-1', - name: 'Menu111Demo', - component: '/demo/level/Menu111', - meta: { - title: 'Menu111', - }, - }, - ], - }, - { - path: 'menu1-2', - name: 'Menu12Demo', - component: '/demo/level/Menu12', - meta: { - title: 'Menu1-2', - }, - }, - ], - }, - { - path: 'menu2', - name: 'Menu2Demo', - component: '/demo/level/Menu2', - meta: { - title: 'Menu2', - }, - }, - ], -} - -const sysRoute = { - path: '/system', - name: 'System', - component: 'LAYOUT', - redirect: '/system/account', - meta: { - icon: 'ion:settings-outline', - title: 'routes.demo.system.moduleName', - }, - children: [ - { - path: 'account', - name: 'AccountManagement', - meta: { - title: 'routes.demo.system.account', - ignoreKeepAlive: true, - }, - component: '/demo/system/account/index', - }, - { - path: 'account_detail/:id', - name: 'AccountDetail', - meta: { - hideMenu: true, - title: 'routes.demo.system.account_detail', - ignoreKeepAlive: true, - showMenu: false, - currentActiveMenu: '/system/account', - }, - component: '/demo/system/account/AccountDetail', - }, - { - path: 'role', - name: 'RoleManagement', - meta: { - title: 'routes.demo.system.role', - ignoreKeepAlive: true, - }, - component: '/demo/system/role/index', - }, - { - path: 'dept', - name: 'DeptManagement', - meta: { - title: 'routes.demo.system.dept', - ignoreKeepAlive: true, - }, - component: '/demo/system/dept/index', - }, - { - path: 'changePassword', - name: 'ChangePassword', - meta: { - title: 'routes.demo.system.password', - ignoreKeepAlive: true, - }, - component: '/demo/system/password/index', - }, - ], -} - -const linkRoute = { - path: '/link', - name: 'Link', - component: 'LAYOUT', - meta: { - icon: 'ion:tv-outline', - title: 'routes.demo.iframe.frame', - }, - children: [ - { - path: 'doc', - name: 'Doc', - meta: { - title: 'routes.demo.iframe.doc', - frameSrc: 'https://vvbin.cn/doc-next/', - }, - }, - { - path: 'https://vvbin.cn/doc-next/', - name: 'DocExternal', - component: 'LAYOUT', - meta: { - title: 'routes.demo.iframe.docExternal', - }, - }, - ], -} - -export default [ - { - url: '/api/getMenuList', - timeout: 1000, - method: 'get', - response: (request: requestParams) => { - const token = getRequestToken(request) - if (!token) { - return resultError('Invalid token!') - } - const checkUser = createFakeUserList().find((item) => item.token === token) - if (!checkUser) { - return resultError('Invalid user token!') - } - const id = checkUser.userId - let menu: Object[] - switch (id) { - case '1': - dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[0].path - menu = [dashboardRoute, authRoute, levelRoute, sysRoute, linkRoute] - break - case '2': - dashboardRoute.redirect = dashboardRoute.path + '/' + dashboardRoute.children[1].path - menu = [dashboardRoute, authRoute, levelRoute, linkRoute] - break - default: - menu = [] - } - - return resultSuccess(menu) - }, - }, -] as MockMethod[] diff --git a/frontend/vben/mock/sys/user.ts b/frontend/vben/mock/sys/user.ts index b5900b5..d6b0f9b 100644 --- a/frontend/vben/mock/sys/user.ts +++ b/frontend/vben/mock/sys/user.ts @@ -1,5 +1,4 @@ import { MockMethod } from 'vite-plugin-mock' -import md5 from 'md5' import { resultError, resultSuccess, getRequestToken, requestParams } from '../_util' export function createFakeUserList() { @@ -61,26 +60,22 @@ const fakeCodeList: any = { '2': ['2000', '4000', '6000'], } export default [ - { + /*{ url: '/api/getLoginSalt', timeout: 200, method: 'get', response: () => { return resultSuccess({ salt: 'nc8w9f82hfioq2ci9hcwehcq' }) }, - }, + },*/ // mock user login - { + /*{ url: '/api/login', timeout: 200, method: 'post', response: ({ body }) => { - const { username, password } = body - const checkUser = createFakeUserList().find( - (item) => - item.username === username && - password === md5(item.password + 'nc8w9f82hfioq2ci9hcwehcq'), - ) + const { username } = body + const checkUser = createFakeUserList().find((item) => item.username === username) if (!checkUser) { return resultError('Incorrect account or password!') } @@ -94,7 +89,7 @@ export default [ desc, }) }, - }, + },*/ // mock reset password { url: '/api/resetPassword', @@ -119,19 +114,19 @@ export default [ }) }, }, - { + /*{ url: '/api/getUserInfo', method: 'get', response: (request: requestParams) => { const token = getRequestToken(request) if (!token) return resultError('Invalid token') - const checkUser = createFakeUserList().find((item) => item.token === token) + const checkUser = createFakeUserList()[0] if (!checkUser) { return resultError('The corresponding user information was not obtained!') } return resultSuccess(checkUser) }, - }, + },*/ { url: '/api/getPermCode', timeout: 200, diff --git a/go.mod b/go.mod index 4d5a863..b50f7ac 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,26 @@ module github.com/fumiama/paper-manager go 1.20 -require github.com/sirupsen/logrus v1.9.0 +require ( + github.com/FloatTech/sqlite v1.6.0 + github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b + github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e + github.com/fumiama/go-base16384 v1.6.4 + github.com/sirupsen/logrus v1.9.0 +) -require golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect +require ( + github.com/google/uuid v1.3.0 // indirect + github.com/mattn/go-isatty v0.0.16 // indirect + github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect + golang.org/x/text v0.3.7 // indirect + modernc.org/libc v1.21.5 // indirect + modernc.org/mathutil v1.5.0 // indirect + modernc.org/memory v1.4.0 // indirect + modernc.org/sqlite v1.20.0 // indirect +) + +replace modernc.org/sqlite => github.com/fumiama/sqlite3 v1.20.0-with-win386 + +replace github.com/remyoudompheng/bigfft => github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b diff --git a/go.sum b/go.sum index ed65537..38886bc 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,42 @@ +github.com/FloatTech/sqlite v1.6.0 h1:YJpd+DClVseBWeWz7VF5gNhlTly6Fg0Ds1j7yHp3Nu0= +github.com/FloatTech/sqlite v1.6.0/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY= +github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw= +github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs= +github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA= +github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b h1:Zt3pFQditAdWTHCOVkiloc9ZauBoWrb37guFV4iIRvE= +github.com/fumiama/bigfft v0.0.0-20211011143303-6e0bfa3c836b/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/fumiama/go-base16384 v1.6.4 h1:rYDRwD/th2cG4U7QLokpzmST1cCxZGXtHmolOUePt5o= +github.com/fumiama/go-base16384 v1.6.4/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM= +github.com/fumiama/sqlite3 v1.20.0-with-win386 h1:ZR1AXGBEtkfq9GAXehOVcwn+aaCG8itrkgEsz4ggx5k= +github.com/fumiama/sqlite3 v1.20.0-with-win386/go.mod h1:Os58MHwYCcYZCy2PGChBrQtBAw5/LS1ZZOkfc+C/I7s= +github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= +github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +modernc.org/libc v1.21.5 h1:xBkU9fnHV+hvZuPSRszN0AXDG4M7nwPLwTWwkYcvLCI= +modernc.org/libc v1.21.5/go.mod h1:przBsL5RDOZajTVslkugzLBj1evTue36jEomFQOoYuI= +modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ= +modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= +modernc.org/memory v1.4.0 h1:crykUfNSnMAXaOJnnxcSzbUGMqkLWjklJKkBK2nwZwk= +modernc.org/memory v1.4.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=