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.
master
vasyahacker 2023-04-17 17:27:11 +04:00
parent e1d8fd4bcc
commit f4acf890d8
5 changed files with 71 additions and 49 deletions

View File

@ -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:], "/")

View File

@ -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)
}

View File

@ -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
})

View File

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

View File

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