openidec

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

commit ef3e6a911e74b05bd6f18fe85560fba1246635c0
parent 5cf59b8bbeff9cea21ffc42f5bc37053542359db
Author: Peter Kosyh <p.kosyh@gmail.com>
Date:   Tue,  1 Sep 2020 23:10:12 +0300

u/point scheme

Diffstat:
Mii-node/main.go | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Mii-tool/main.go | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mii/db.go | 127+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Mii/msg.go | 7+++++--
Mii/net.go | 50++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 292 insertions(+), 5 deletions(-)

diff --git a/ii-node/main.go b/ii-node/main.go @@ -19,6 +19,26 @@ func open_db(path string) *ii.DB { return db } +func PointMsg(db *ii.DB, pauth string, tmsg string) string { + udb := ii.LoadUsers(db.BundlePath() + ".usr") + if !udb.Access(pauth) { + ii.Info.Printf("Access denied for pauth: %s", pauth) + return "Access denied" + } + m, err := ii.DecodeMsgline(tmsg, true) + if err != nil { + ii.Error.Printf("Receive point msg: %s", err) + return fmt.Sprintf("%s", err) + } + m.From = udb.Name(pauth) + m.Addr = fmt.Sprintf("%s,%d", db.Name, udb.Id(pauth)) + if err := db.Store(m); err != nil { + ii.Error.Printf("Store point msg: %s", err) + return fmt.Sprintf("%s", err) + } + return "msg ok" +} + func main() { ii.OpenLog(ioutil.Discard, os.Stdout, os.Stderr) @@ -35,6 +55,38 @@ func main() { fmt.Fprintf(w, "%s:%d:\n", v.Name, v.Count) } }) + http.HandleFunc("/u/point/", func(w http.ResponseWriter, r *http.Request) { + var pauth, tmsg string + switch r.Method { + case "GET": + args := strings.Split(r.URL.Path[9:], "/") + if len(args) != 2 { + ii.Error.Printf("Wrong /u/point/ get request") + return + } + pauth, tmsg = args[0], args[1] + default: + return + } + ii.Info.Printf("/u/point/%s/%s GET request", pauth, tmsg) + fmt.Fprintf(w, PointMsg(db, pauth, tmsg)) + }) + http.HandleFunc("/u/point", func(w http.ResponseWriter, r *http.Request) { + var pauth, 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") + tmsg = r.FormValue("tmsg") + default: + return + } + ii.Info.Printf("/u/point/%s/%s POST request", pauth, tmsg) + fmt.Fprintf(w, PointMsg(db, pauth, tmsg)) + }) http.HandleFunc("/x/c/", func(w http.ResponseWriter, r *http.Request) { enames := strings.Split(r.URL.Path[5:], "/") echoes := db.Echoes(enames) diff --git a/ii-tool/main.go b/ii-tool/main.go @@ -20,6 +20,36 @@ func open_db(path string) *ii.DB { return db } +func open_users_db(path string) *ii.UDB { + db := ii.LoadUsers(path) + if db == nil { + fmt.Printf("Can no open db: %s\n", path) + os.Exit(1) + } + return db +} + +func GetFile(path string) string { + var file *os.File + var err error + if path == "-" { + file = os.Stdin + } else { + file, err = os.Open(path) + if err != nil { + fmt.Printf("Can not open file %s: %s\n", path, err) + os.Exit(1) + } + defer file.Close() + } + b, err := ioutil.ReadAll(file) + if err != nil { + fmt.Printf("Can not read file %s: %s\n", path, err) + os.Exit(1) + } + return string(b) +} + func main() { ii.OpenLog(ioutil.Discard, os.Stdout, os.Stderr) @@ -35,11 +65,13 @@ func main() { if len(args) < 1 { fmt.Printf(`Help: %s [options] command [arguments] Commands: + send <server> <pauth> <msg|-> - send message fetch <url> - fetch store <bundle|-> - import bundle to database get <msgid> - show message from database select <echo> [[start]:lim] - get slice from echo index - recreate index + useradd <name> <e-mail> <password> - adduser Options: -db=<path> - database path -lim=<lim> - fetch lim last messages @@ -47,6 +79,35 @@ Options: os.Exit(1) } switch cmd := args[0]; cmd { + case "send": + if len(args) < 4 { + fmt.Printf("No argumnet(s) supplied\nShould be: <server> <pauth> and <file|->.\n") + os.Exit(1) + } + msg := GetFile(args[3]) + if _, err := ii.DecodeMsgline(string(msg), false); err != nil { + fmt.Printf("Wrong message format\n") + os.Exit(1) + } + n, err := ii.Connect(args[1]) + if err != nil { + fmt.Printf("Can not connect to %s: %s\n", args[1], err) + os.Exit(1) + } + if err := n.Post(args[2], msg); err != nil { + fmt.Printf("Can not send message: %s\n", err) + os.Exit(1) + } + case "useradd": + if len(args) < 4 { + fmt.Printf("No argumnet(s) supplied\nShould be: name, e-mail and password.\n") + os.Exit(1) + } + db := open_users_db(*db_opt + ".usr") + if err := db.Add(args[1], args[2], args[3]); err != nil { + fmt.Printf("Can not add user: %s\n", err) + os.Exit(1) + } case "fetch": if len(args) < 2 { fmt.Printf("No url supplied\n") diff --git a/ii/db.go b/ii/db.go @@ -2,6 +2,8 @@ package ii import ( "bufio" + "crypto/sha256" + "encoding/base64" "errors" "fmt" "io" @@ -30,6 +32,7 @@ type DB struct { Path string Idx Index Sync sync.RWMutex + Name string } func mkdir(path string) { @@ -58,6 +61,7 @@ func (db *DB) Lock() bool { time.Sleep(time.Second) try -= 1 } + Error.Printf("Can not acquire lock for 16 seconds") return false } @@ -435,13 +439,13 @@ func (db *DB) _Store(m *Msg, edit bool) error { defer db.Sync.Unlock() db.Lock() defer db.Unlock() - if _, ok := db.Idx.Hash[m.MsgId]; ok && !edit { // exist and not edit - return errors.New("Already exists") - } repto, _ := m.Tag("repto") if err := db.LoadIndex(); err != nil { return err } + if _, ok := db.Idx.Hash[m.MsgId]; ok && !edit { // exist and not edit + return errors.New("Already exists") + } fi, err := os.Stat(db.BundlePath()) var off int64 if err == nil { @@ -474,6 +478,123 @@ func OpenDB(path string) *DB { if err != nil || !info.IsDir() { return nil } + db.Name = "node" // db.Idx = make(map[string]Index) return &db } + +type User struct { + Id int32 + Name string + Mail string + Secret string + Tags Tags +} + +type UDB struct { + Path string + Names map[string]User + Secrets map[string]string + List []string + Sync sync.Mutex +} + +func IsUsername(u string) bool { + return !strings.ContainsAny(u, ":\n\r\t") && len(u) <= 16 +} + +func MakeSecret(msg string) string { + h := sha256.Sum256([]byte(msg)) + s := base64.URLEncoding.EncodeToString(h[:]) + return s[0:10] +} + +func (db *UDB) Access(Secret string) bool { + _, ok := db.Secrets[Secret] + return ok +} + +func (db *UDB) Name(Secret string) string { + name, ok := db.Secrets[Secret] + if ok { + return name + } + Error.Printf("No user for secret: %s", Secret) + return "" +} + +func (db *UDB) Id(Secret string) int32 { + name, ok := db.Secrets[Secret] + if ok { + v, ok := db.Names[name] + if !ok { + return -1 + } + return v.Id + } + Error.Printf("No user for secret: %s", Secret) + return -1 +} + +func (db *UDB) Add(Name string, Mail string, Passwd string) error { + db.Sync.Lock() + defer db.Sync.Unlock() + + if _, ok := db.Names[Name]; ok { + return errors.New("Already exists") + } + if !IsUsername(Name) { + return errors.New("Wrong username") + } + var id int32 = 0 + for _, v := range db.Names { + if v.Id > id { + id = v.Id + } + } + id++ + var u User + u.Name = Name + u.Mail = Mail + u.Secret = MakeSecret(string(id) + Name + Passwd) + u.Tags = NewTags("") + db.List = append(db.List, u.Name) + if err := append_file(db.Path, fmt.Sprintf("%d:%s:%s:%s:%s", + id, Name, Mail, u.Secret, u.Tags.String())); err != nil { + return err + } + return nil +} + +func LoadUsers(path string) *UDB { + var db UDB + db.Path = path + db.Names = make(map[string]User) + db.Secrets = make(map[string]string) + err := file_lines(path, func(line string) bool { + a := strings.Split(line, ":") + if len(a) < 4 { + Error.Printf("Wrong entry in user DB: %s", line) + return true + } + var u User + var err error + _, err = fmt.Sscanf(a[0], "%d", &u.Id) + if err != nil { + Error.Printf("Wrong ID in user DB: %s", a[0]) + return true + } + u.Name = a[1] + u.Mail = a[2] + u.Secret = a[3] + u.Tags = NewTags(a[4]) + db.Names[u.Name] = u + db.Secrets[u.Secret] = u.Name + db.List = append(db.List, u.Name) + return true + }) + if err != nil { + return nil + } + return &db +} diff --git a/ii/msg.go b/ii/msg.go @@ -5,6 +5,7 @@ import ( "encoding/base64" "errors" "fmt" + "net/url" "strings" "time" ) @@ -48,8 +49,10 @@ func DecodeMsgline(msg string, enc bool) (*Msg, error) { var data []byte var err error if enc { - data, err = base64.StdEncoding.DecodeString(msg) - if err != nil { + if msg, err = url.QueryUnescape(msg); err != nil { + return nil, err + } + if data, err = base64.StdEncoding.DecodeString(msg); err != nil { return nil, err } } else { diff --git a/ii/net.go b/ii/net.go @@ -2,9 +2,13 @@ package ii import ( "bufio" + "encoding/base64" + "errors" "fmt" "io" + "io/ioutil" "net/http" + "net/url" "strings" "sync" ) @@ -109,6 +113,52 @@ func (n *Node) Fetcher(db *DB, Echo string, limit int, wait *sync.WaitGroup, con var MaxConnections = 6 +func (n *Node) Send(pauth string, msg string) error { + msg = base64.StdEncoding.EncodeToString([]byte(msg)) + req := fmt.Sprintf("%s/u/point/%s/%s", n.Host, pauth, msg) + resp, err := http.Get(req) + Trace.Printf("Get %s", req) + if err != nil { + return err + } + buf, err := ioutil.ReadAll(resp.Body) + if strings.HasPrefix(string(buf), "msg ok") { + Trace.Printf("Server responced msg ok") + return nil + } else if len(buf) > 0 { + err = errors.New(string(buf)) + } + if err == nil { + err = errors.New("Server did not response with ok") + } + return err +} + +func (n *Node) Post(pauth string, msg string) error { + msg = base64.StdEncoding.EncodeToString([]byte(msg)) + msg = url.QueryEscape(msg) + postData := url.Values{ + "pauth": {pauth}, + "tmsg": {msg}, + } + resp, err := http.PostForm(n.Host+"/u/point", postData) + Trace.Printf("Post %s/u/point", n.Host) + if err != nil { + return err + } + buf, err := ioutil.ReadAll(resp.Body) + if strings.HasPrefix(string(buf), "msg ok") { + Trace.Printf("Server responced msg ok") + return nil + } else if len(buf) > 0 { + err = errors.New(string(buf)) + } + if err == nil { + err = errors.New("Server did not response with ok") + } + return err +} + func (n *Node) List() ([]string, error) { var list []string if !n.IsFeature("list.txt") {