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 }