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
parent
e1d8fd4bcc
commit
f4acf890d8
|
@ -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:], "/")
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
44
ii/db.go
44
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
|
||||
})
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue