commit ef3e6a911e74b05bd6f18fe85560fba1246635c0
parent 5cf59b8bbeff9cea21ffc42f5bc37053542359db
Author: Peter Kosyh <p.kosyh@gmail.com>
Date: Tue, 1 Sep 2020 23:10:12 +0300
u/point scheme
Diffstat:
| M | ii-node/main.go | | | 52 | ++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | ii-tool/main.go | | | 61 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| M | ii/db.go | | | 127 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
| M | ii/msg.go | | | 7 | +++++-- |
| M | ii/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") {