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:
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>