openidec

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit f4acf890d8a3494fb7757579b7e5321603125095
parent e1d8fd4bcc9889bd47b195273a5489dcd7a713e4
Author: vasyahacker <vasya@magicfreedom.com>
Date:   Mon, 17 Apr 2023 17:27:11 +0400

Instead of the first 10 bytes of sha256 from the password, a randomly generated 16-byte token is used tto store in
the cookie. When you log out, all user sessions are reset. When idecd is restarted, all users will be logged out.

Diffstat:
Mcmd/idecd/main.go | 34+++++++++++++++++-----------------
Mcmd/idecd/web.go | 36+++++++++++++++++++++++++++++-------
Mii/db.go | 44++++++++++++++++++++++----------------------
Mwww/tpl/profile.tpl | 2+-
Mwww/tpl/reset.tpl | 4++--
5 files changed, 71 insertions(+), 49 deletions(-)

diff --git a/cmd/idecd/main.go b/cmd/idecd/main.go @@ -23,15 +23,15 @@ func open_db(path string) *ii.DB { return db } -func PointMsg(edb *ii.EDB, db *ii.DB, udb *ii.UDB, pauth string, tmsg string) string { +func PointMsg(edb *ii.EDB, db *ii.DB, udb *ii.UDB, token string, tmsg string) string { err := udb.LoadUsers() if err != nil { ii.Error.Printf("Error loading users: %s", err) return err.Error() } - if !udb.Access(pauth) { - ii.Info.Printf("Access denied for pauth: %s", pauth) + if !udb.Access(token) { + ii.Info.Printf("Access denied for token: %s", token) return "Access denied" } m, err := ii.DecodeMsgline(tmsg, true) @@ -50,8 +50,8 @@ func PointMsg(edb *ii.EDB, db *ii.DB, udb *ii.UDB, pauth string, tmsg string) st return "This echo is disallowed" } - m.From = udb.Name(pauth) - m.Addr = fmt.Sprintf("%s,%d", db.Name, udb.Id(pauth)) + m.From = udb.Name(token) + m.Addr = fmt.Sprintf("%s,%d", db.Name, udb.Id(token)) if err := db.Store(m); err != nil { ii.Error.Printf("Store point msg: %s", err) return err.Error() @@ -166,7 +166,7 @@ func main() { handleWWW(&www, w, r) }) http.HandleFunc("/u/point/", func(w http.ResponseWriter, r *http.Request) { - var pauth, tmsg string + var token, tmsg string switch r.Method { case "GET": err := udb.LoadUsers() @@ -177,12 +177,12 @@ func main() { args := strings.Split(r.URL.Path[9:], "/") if len(args) >= 3 && args[1] == "u" { - pauth = args[0] - if !udb.Access(pauth) { - ii.Info.Printf("Access denied for pauth: %s", pauth) + token = args[0] + if !udb.Access(token) { + ii.Info.Printf("Access denied for token: %s", token) return } - user := udb.UserInfo(pauth) + user := udb.UserInfo(token) if user == nil { return } @@ -209,28 +209,28 @@ func main() { ii.Error.Printf("Wrong /u/point/ get request: %s", r.URL.Path[9:]) return } - pauth, tmsg = args[0], args[1] + token, tmsg = args[0], args[1] default: return } - ii.Info.Printf("/u/point/%s/%s GET request", pauth, tmsg) - fmt.Fprint(w, PointMsg(edb, db, udb, pauth, tmsg)) + ii.Info.Printf("/u/point/%s/%s GET request", token, tmsg) + fmt.Fprint(w, PointMsg(edb, db, udb, token, tmsg)) }) http.HandleFunc("/u/point", func(w http.ResponseWriter, r *http.Request) { - var pauth, tmsg string + var token, tmsg string switch r.Method { case "POST": if err := r.ParseForm(); err != nil { ii.Error.Printf("Error in POST request: %s", err) return } - pauth = r.FormValue("pauth") + token = r.FormValue("token") tmsg = r.FormValue("tmsg") default: return } - ii.Info.Printf("/u/point/%s/%s POST request", pauth, tmsg) - fmt.Fprint(w, PointMsg(edb, db, udb, pauth, tmsg)) + ii.Info.Printf("/u/point/%s/%s POST request", token, tmsg) + fmt.Fprint(w, PointMsg(edb, db, udb, token, tmsg)) }) http.HandleFunc("/x/c/", func(w http.ResponseWriter, r *http.Request) { enames := strings.Split(r.URL.Path[5:], "/") diff --git a/cmd/idecd/web.go b/cmd/idecd/web.go @@ -13,6 +13,8 @@ import ( "sort" "strings" "time" + "encoding/hex" + "crypto/rand" "git.openbsd.org.ru/vasyahacker/openidec/ii" ) @@ -55,9 +57,9 @@ func www_register(ctx *WebContext, w http.ResponseWriter, r *http.Request) error ii.Error.Printf("Error in POST request: %s", err) return err } - auth := r.FormValue("auth") - if auth != "" { /* edit form */ - u := udb.UserInfo(auth) + token := r.FormValue("token") + if token != "" { /* edit form */ + u := udb.UserInfo(token) if u == nil { ii.Error.Printf("Access denied") return errors.New("Access denied") @@ -108,7 +110,12 @@ func www_login(ctx *WebContext, w http.ResponseWriter, r *http.Request) error { return errors.New("Access denied") } exp := time.Now().Add(10 * 365 * 24 * time.Hour) - cookie := http.Cookie{Name: "pauth", Value: udb.Secret(user), Expires: exp} + u := udb.UserInfoName(user) + token := generateSecureToken(16) + u.Token = token + udb.Tokens[token] = user + udb.Names[user] = *u + cookie := http.Cookie{Name: "token", Value: token, Expires: exp} http.SetCookie(w, &cookie) ii.Info.Printf("User logged in: %s\n", user) http.Redirect(w, r, ctx.PfxPath+"/", http.StatusSeeOther) @@ -141,8 +148,15 @@ func www_logout(ctx *WebContext, w http.ResponseWriter, r *http.Request) error { ii.Error.Printf("Access denied") return errors.New("Access denied") } - cookie := http.Cookie{Name: "pauth", Value: "", Expires: time.Unix(0, 0)} - http.SetCookie(w, &cookie) + cookie, err := r.Cookie("token") + if err == nil { + udb := ctx.www.udb + if udb.Access(cookie.Value) { + delete(ctx.www.udb.Tokens, cookie.Value) + } + } + rmcookie := http.Cookie{Name: "token", Value: "", Expires: time.Unix(0, 0)} + http.SetCookie(w, &rmcookie) http.Redirect(w, r, ctx.PfxPath+"/", http.StatusSeeOther) return nil } @@ -951,7 +965,7 @@ func handleWWW(www *WWW, w http.ResponseWriter, r *http.Request) { } func _handleWWW(ctx *WebContext, w http.ResponseWriter, r *http.Request) error { - cookie, err := r.Cookie("pauth") + cookie, err := r.Cookie("token") if err == nil { udb := ctx.www.udb if udb.Access(cookie.Value) { @@ -1086,3 +1100,11 @@ func _handleWWW(ctx *WebContext, w http.ResponseWriter, r *http.Request) error { } return nil } + +func generateSecureToken(length int) string { + b := make([]byte, length) + if _, err := rand.Read(b); err != nil { + return "" + } + return hex.EncodeToString(b) +} diff --git a/ii/db.go b/ii/db.go @@ -870,6 +870,7 @@ type User struct { Name string Mail string Secret string + Token string Tags Tags } @@ -877,13 +878,13 @@ type User struct { // FileSize - size of points.txt to detect DB changes. // Names: holds User structure by user name // ById: holds user name by user id -// Secrets: holds user name by user secret (pauth) +// Tokens: holds user name by user token // List: holds user names as list type UDB struct { Path string Names map[string]User ById map[int32]string - Secrets map[string]string + Tokens map[string]string List []string Sync sync.RWMutex FileSize int64 @@ -914,15 +915,15 @@ func MakeSecret(msg string) string { return string(hash) } -// Return secret for username or "" if no such user -func (db *UDB) Secret(User string) string { +// Return token for username or "" if no such user +func (db *UDB) Token(User string) string { db.Sync.RLock() defer db.Sync.RUnlock() ui, ok := db.Names[User] if !ok { return "" } - return ui.Secret + return ui.Token } // Returns true if user+password is valid @@ -937,36 +938,36 @@ func (db *UDB) Auth(User string, Passwd string) bool { return bcrypt.CompareHashAndPassword([]byte(ui.Secret), secret[:]) == nil } -// Returns true if Secret (pauth) is valid -func (db *UDB) Access(Secret string) bool { +// Returns true if token is valid +func (db *UDB) Access(Token string) bool { db.Sync.RLock() defer db.Sync.RUnlock() - _, ok := db.Secrets[Secret] + _, ok := db.Tokens[Token] return ok } -// Return username for given Secret -func (db *UDB) Name(Secret string) string { +// Return username for given Token +func (db *UDB) Name(Token string) string { db.Sync.RLock() defer db.Sync.RUnlock() - name, ok := db.Secrets[Secret] + name, ok := db.Tokens[Token] if ok { return name } - Error.Printf("No user for secret: %s", Secret) + Error.Printf("No user for Token: %s", Token) return "" } -// Return User pointer for given Secret -func (db *UDB) UserInfo(Secret string) *User { +// Return User pointer for given Token +func (db *UDB) UserInfo(Token string) *User { db.Sync.RLock() defer db.Sync.RUnlock() - name, ok := db.Secrets[Secret] + name, ok := db.Tokens[Token] if ok { v := db.Names[name] return &v } - Error.Printf("No user for secret: %s", Secret) + Error.Printf("No user for token: %s", Token) return nil } @@ -994,11 +995,11 @@ func (db *UDB) UserInfoName(name string) *User { return nil } -// Return user id for given secret -func (db *UDB) Id(Secret string) int32 { +// Return user id for given token +func (db *UDB) Id(token string) int32 { db.Sync.RLock() defer db.Sync.RUnlock() - name, ok := db.Secrets[Secret] + name, ok := db.Tokens[token] if ok { v, ok := db.Names[name] if !ok { @@ -1006,7 +1007,7 @@ func (db *UDB) Id(Secret string) int32 { } return v.Id } - Error.Printf("No user for secret: %s", Secret) + Error.Printf("No user for token: %s", token) return -1 } @@ -1107,7 +1108,7 @@ func (db *UDB) LoadUsers() error { return nil } db.Names = make(map[string]User) - db.Secrets = make(map[string]string) + db.Tokens = make(map[string]string) db.ById = make(map[int32]string) db.List = nil err = FileLines(db.Path, func(line string) bool { @@ -1129,7 +1130,6 @@ func (db *UDB) LoadUsers() error { u.Tags = NewTags(a[4]) db.ById[u.Id] = u.Name db.Names[u.Name] = u - db.Secrets[u.Secret] = u.Name db.List = append(db.List, u.Name) return true }) diff --git a/www/tpl/profile.tpl b/www/tpl/profile.tpl @@ -3,7 +3,7 @@ <table id="profile" cellspacing=0 cellpadding=0> {{if has_avatar .User.Name}}<img class="avatar" src="/avatar/{{.User.Name}}">{{end}} <tr class="odd"><td>Login:</td><td>{{.User.Name}}</td></tr> -<tr class="even"><td>Auth:</td><td>{{.User.Secret}}</td></tr> +<tr class="even"><td>Token:</td><td>{{.User.Token}}</td></tr> <tr class="odd"><td>e-mail:</td><td>{{.User.Mail}}</td></tr> <tr class="even"><td>Addr:</td><td>{{.Selected}}</td></tr> <tr class="odd"><td class="links" colspan="2"><a href="{{.PfxPath}}/from/{{.User.Name}}">/from/{{.User.Name}}</a> :: <a href="{{.PfxPath}}/to/{{.User.Name}}">/to/{{.User.Name}}</a> diff --git a/www/tpl/reset.tpl b/www/tpl/reset.tpl @@ -3,7 +3,7 @@ <table id="login" cellspacing=0 cellpadding=0> <tr class="odd"><td> -<input type="text" name="auth" class="login" placeholder="authstr" value="{{.User.Secret}}"><br> +<input type="text" name="token" class="login" placeholder="authstr" value="{{.User.Token}}"><br> </td></tr> <tr class="even"><td> @@ -11,7 +11,7 @@ </td></tr> <tr class="odd"><td class="links"> -<button class="form-button">Register</button> +<button class="form-button">Save</button> </td></tr> </table>