openidec

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

main.go (7632B)


      1 package main
      2 
      3 import (
      4 	"errors"
      5 	"flag"
      6 	"fmt"
      7 	"html/template"
      8 	"io/ioutil"
      9 	"net/http"
     10 	"os"
     11 	"path/filepath"
     12 	"strings"
     13 
     14 	"git.openbsd.org.ru/vasyahacker/openidec/ii"
     15 )
     16 
     17 func open_db(path string) *ii.DB {
     18 	db := ii.OpenDB(path)
     19 	if db == nil {
     20 		ii.Error.Printf("Can no open db: %s\n", path)
     21 		os.Exit(1)
     22 	}
     23 	return db
     24 }
     25 
     26 func PointMsg(edb *ii.EDB, db *ii.DB, udb *ii.UDB, token string, tmsg string) string {
     27 	err := udb.LoadUsers()
     28 	if err != nil {
     29 		ii.Error.Printf("Error loading users: %s", err)
     30 		return err.Error()
     31 	}
     32 
     33 	if !udb.Access(token) {
     34 		ii.Info.Printf("Access denied for token: %s", token)
     35 		return "Access denied"
     36 	}
     37 	m, err := ii.DecodeMsgline(tmsg, true)
     38 	if err != nil {
     39 		ii.Error.Printf("Receive point msg: %s", err)
     40 		return err.Error()
     41 	}
     42 	if r, _ := m.Tag("repto"); r != "" {
     43 		if db.Lookup(r) == nil {
     44 			ii.Error.Printf("Receive point msg with wrong repto.")
     45 			return "Receive point msg with wrong repto."
     46 		}
     47 	}
     48 	if !edb.Allowed(m.Echo) {
     49 		ii.Error.Printf("This echo is disallowed")
     50 		return "This echo is disallowed"
     51 	}
     52 
     53 	m.From = udb.Name(token)
     54 	m.Addr = fmt.Sprintf("%s,%d", db.Name, udb.Id(token))
     55 	if err := db.Store(m); err != nil {
     56 		ii.Error.Printf("Store point msg: %s", err)
     57 		return err.Error()
     58 	}
     59 	return "msg ok"
     60 }
     61 
     62 var users_opt *string = flag.String("u", "points.txt", "Users database")
     63 var db_opt *string = flag.String("db", "./db", "II database path (directory)")
     64 var listen_opt *string = flag.String("L", ":8080", "Listen address")
     65 var sysname_opt *string = flag.String("sys", "OpenIDEC", "Node name")
     66 var host_opt *string = flag.String("host", "http://127.0.0.1:8080", "Node address")
     67 var verbose_opt *bool = flag.Bool("v", false, "Verbose")
     68 var noreg_opt *bool = flag.Bool("noreg", false, "Disable new users registration")
     69 var echo_opt *string = flag.String("e", "list.txt", "Echoes list")
     70 var tpl_path_opt *string = flag.String("tpl", "./tpl", "Path to html templates")
     71 var style_path_opt *string = flag.String("style", "./style", "Path to /style web-directory (css/images)")
     72 
     73 type WWW struct {
     74 	Host  string
     75 	tplp  string // templates path
     76 	noreg bool
     77 	tpl   *template.Template
     78 	db    *ii.DB
     79 	edb   *ii.EDB
     80 	udb   *ii.UDB
     81 }
     82 
     83 func get_ue(echoes []string, db *ii.DB, user ii.User, w http.ResponseWriter, r *http.Request) {
     84 	if len(echoes) == 0 {
     85 		return
     86 	}
     87 	slice := echoes[len(echoes)-1:][0]
     88 	var idx, lim int
     89 	if _, err := fmt.Sscanf(slice, "%d:%d", &idx, &lim); err == nil {
     90 		echoes = echoes[:len(echoes)-1]
     91 	} else {
     92 		idx, lim = 0, 0
     93 	}
     94 
     95 	for _, e := range echoes {
     96 		if !ii.IsEcho(e) {
     97 			continue
     98 		}
     99 		fmt.Fprintf(w, "%s\n", e)
    100 		ids := db.SelectIDS(ii.Query{Echo: e, Start: idx, Lim: lim, User: user})
    101 		for _, id := range ids {
    102 			fmt.Fprintf(w, "%s\n", id)
    103 		}
    104 	}
    105 
    106 }
    107 func main() {
    108 	var www WWW
    109 	ii.OpenLog(ioutil.Discard, os.Stdout, os.Stderr)
    110 
    111 	flag.Parse()
    112 
    113 	if _, err := os.Stat(*tpl_path_opt); errors.Is(err, os.ErrNotExist) {
    114 		ii.Error.Printf("Templates dir %s not found", *tpl_path_opt)
    115 		os.Exit(1)
    116 	}
    117 
    118 	if _, err := os.Stat(*style_path_opt); errors.Is(err, os.ErrNotExist) {
    119 		ii.Info.Printf("Web share dir %s (for css/images) not found",
    120 			*style_path_opt)
    121 	}
    122 
    123 	unveil(*tpl_path_opt, "r")
    124 	unveil(*style_path_opt, "r")
    125 	unveil(*echo_opt, "r")				// list.txt
    126 	unveil(*users_opt, "rwc")			// points.txt
    127 	unveil(filepath.Dir(*db_opt), "rwc")// db dir
    128 	unveil(*db_opt+".idx", "rwc")		// db index
    129 	unveil(os.TempDir(), "rwc")
    130 	unveil_block()
    131 
    132 	db := open_db(*db_opt)
    133 	edb := ii.LoadEcholist(*echo_opt)
    134 	udb := ii.OpenUsers(*users_opt)
    135 	if *verbose_opt {
    136 		ii.OpenLog(os.Stdout, os.Stdout, os.Stderr)
    137 	}
    138 
    139 	db.Name = *sysname_opt
    140 	www.tplp = *tpl_path_opt
    141 	www.db = db
    142 	www.edb = edb
    143 	www.udb = udb
    144 	www.Host = *host_opt
    145 	www.noreg = *noreg_opt
    146 	WebInit(&www)
    147 
    148 	fs := http.FileServer(http.Dir(*style_path_opt))
    149 	http.Handle("/style/", http.StripPrefix("/style/", fs))
    150 
    151 	http.HandleFunc("/list.txt", func(w http.ResponseWriter, r *http.Request) {
    152 		echoes := db.Echoes(nil, ii.Query{})
    153 		for _, v := range echoes {
    154 			if !ii.IsPrivate(v.Name) {
    155 				fmt.Fprintf(w, "%s:%d:%s\n", v.Name, v.Count, www.edb.Info[v.Name])
    156 			}
    157 		}
    158 	})
    159 	http.HandleFunc("/blacklist.txt", func(w http.ResponseWriter, r *http.Request) {
    160 		ids := db.SelectIDS(ii.Query{Blacklisted: true})
    161 		for _, v := range ids {
    162 			fmt.Fprintf(w, "%s\n", v)
    163 		}
    164 	})
    165 	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    166 		handleWWW(&www, w, r)
    167 	})
    168 	http.HandleFunc("/u/point/", func(w http.ResponseWriter, r *http.Request) {
    169 		var token, tmsg string
    170 		switch r.Method {
    171 		case "GET":
    172 			err := udb.LoadUsers()
    173 			if err != nil {
    174 				ii.Error.Printf("Error loaging users: %s", err)
    175 				return
    176 			}
    177 			args := strings.Split(r.URL.Path[9:], "/")
    178 
    179 			if len(args) >= 3 && args[1] == "u" {
    180 				token = args[0]
    181 				if !udb.Access(token) {
    182 					ii.Info.Printf("Access denied for token: %s", token)
    183 					return
    184 				}
    185 				user := udb.UserInfo(token)
    186 				if user == nil {
    187 					return
    188 				}
    189 				if args[2] == "e" {
    190 					echoes := args[3:]
    191 					get_ue(echoes, db, *user, w, r)
    192 					return
    193 				}
    194 				if args[2] == "m" {
    195 					ids := args[3:]
    196 					for _, i := range ids {
    197 						m, info := db.GetBundleInfo(i)
    198 						if m == "" || !db.Access(info, user) {
    199 							continue
    200 						}
    201 						fmt.Fprintf(w, "%s\n", m)
    202 					}
    203 					return
    204 				}
    205 				ii.Error.Printf("Wrong /u/point/ get request: %s", r.URL.Path[9:])
    206 				return
    207 			}
    208 			if len(args) != 2 {
    209 				ii.Error.Printf("Wrong /u/point/ get request: %s", r.URL.Path[9:])
    210 				return
    211 			}
    212 			token, tmsg = args[0], args[1]
    213 		default:
    214 			return
    215 		}
    216 		ii.Info.Printf("/u/point/%s/%s GET request", token, tmsg)
    217 		fmt.Fprint(w, PointMsg(edb, db, udb, token, tmsg))
    218 	})
    219 	http.HandleFunc("/u/point", func(w http.ResponseWriter, r *http.Request) {
    220 		var token, tmsg string
    221 		switch r.Method {
    222 		case "POST":
    223 			if err := r.ParseForm(); err != nil {
    224 				ii.Error.Printf("Error in POST request: %s", err)
    225 				return
    226 			}
    227 			token = r.FormValue("token")
    228 			tmsg = r.FormValue("tmsg")
    229 		default:
    230 			return
    231 		}
    232 		ii.Info.Printf("/u/point/%s/%s POST request", token, tmsg)
    233 		fmt.Fprint(w, PointMsg(edb, db, udb, token, tmsg))
    234 	})
    235 	http.HandleFunc("/x/c/", func(w http.ResponseWriter, r *http.Request) {
    236 		enames := strings.Split(r.URL.Path[5:], "/")
    237 		echoes := db.Echoes(enames, ii.Query{})
    238 		for _, v := range echoes {
    239 			if !ii.IsPrivate(v.Name) {
    240 				fmt.Fprintf(w, "%s:%d:\n", v.Name, v.Count)
    241 			}
    242 		}
    243 	})
    244 	http.HandleFunc("/u/m/", func(w http.ResponseWriter, r *http.Request) {
    245 		ids := strings.Split(r.URL.Path[5:], "/")
    246 		for _, i := range ids {
    247 			m, info := db.GetBundleInfo(i)
    248 			if m != "" && !ii.IsPrivate(info.Echo) {
    249 				fmt.Fprintf(w, "%s\n", m)
    250 			}
    251 		}
    252 	})
    253 	http.HandleFunc("/u/e/", func(w http.ResponseWriter, r *http.Request) {
    254 		echoes := strings.Split(r.URL.Path[5:], "/")
    255 		get_ue(echoes, db, ii.User{}, w, r)
    256 	})
    257 	http.HandleFunc("/m/", func(w http.ResponseWriter, r *http.Request) {
    258 		id := r.URL.Path[3:]
    259 		if !ii.IsMsgId(id) {
    260 			return
    261 		}
    262 		m := db.Get(id)
    263 		ii.Info.Printf("/m/%s %s", id, m)
    264 		if m != nil && !ii.IsPrivate(m.Echo) {
    265 			fmt.Fprintf(w, "%s", m.String())
    266 		}
    267 	})
    268 	http.HandleFunc("/e/", func(w http.ResponseWriter, r *http.Request) {
    269 		e := r.URL.Path[3:]
    270 		if !ii.IsEcho(e) || ii.IsPrivate(e) {
    271 			return
    272 		}
    273 		ids := db.SelectIDS(ii.Query{Echo: e})
    274 		for _, id := range ids {
    275 			fmt.Fprintf(w, "%s\n", id)
    276 		}
    277 	})
    278 	http.HandleFunc("/x/features", func(w http.ResponseWriter, r *http.Request) {
    279 		fmt.Fprintf(w, "list.txt\nblacklist.txt\nu/e\nx/c\n")
    280 	})
    281 	ii.Info.Printf("Listening on %s", *listen_opt)
    282 
    283 	if err := http.ListenAndServe(*listen_opt, nil); err != nil {
    284 		ii.Error.Printf("Error running web server: %s", err)
    285 	}
    286 }