diff --git a/auth.go b/auth.go new file mode 100644 index 00000000..0ea1163e --- /dev/null +++ b/auth.go @@ -0,0 +1,117 @@ +/* Work in progress */ +package main + +import "log" +import "errors" +import "strconv" +import "net/http" +import "database/sql" + +import "./query_gen/lib" +import "golang.org/x/crypto/bcrypt" + +var auth Auth +var ErrMismatchedHashAndPassword = bcrypt.ErrMismatchedHashAndPassword + +type Auth interface +{ + Authenticate(username string, password string) (int,error) + Logout(w http.ResponseWriter, uid int) + ForceLogout(uid int) error + SetCookies(w http.ResponseWriter, uid int, session string) + CreateSession(uid int) (string, error) +} + +type DefaultAuth struct +{ + login *sql.Stmt + logout *sql.Stmt +} + +func NewDefaultAuth() *DefaultAuth { + login_stmt, err := qgen.Builder.SimpleSelect("users","uid, name, password, salt","name = ?","","") + if err != nil { + log.Fatal(err) + } + logout_stmt, err := qgen.Builder.SimpleUpdate("users","session = ''","uid = ?") + if err != nil { + log.Fatal(err) + } + return &DefaultAuth{ + login: login_stmt, + logout: logout_stmt, + } +} + +func (auth *DefaultAuth) Authenticate(username string, password string) (uid int, err error) { + var real_password, salt string + err = auth.login.QueryRow(username).Scan(&uid, &username, &real_password, &salt) + if err == sql.ErrNoRows { + return 0, errors.New("We couldn't find an account with that username.") + } else if err != nil { + LogError(err) + return 0, errors.New("There was a glitch in the system. Please contact the system administrator.") + } + + if salt == "" { + // Send an email to admin for this? + LogError(errors.New("Missing salt for user #" + strconv.Itoa(uid) + ". Potential security breach.")) + return 0, errors.New("There was a glitch in the system. Please contact the system administrator.") + } + + err = CheckPassword(real_password,password,salt) + if err == ErrMismatchedHashAndPassword { + return 0, errors.New("That's not the correct password.") + } else if err != nil { + LogError(err) + return 0, errors.New("There was a glitch in the system. Please contact the system administrator.") + } + + return uid, nil +} + +func (auth *DefaultAuth) ForceLogout(uid int) error { + _, err := auth.logout.Exec(uid) + if err != nil { + LogError(err) + return errors.New("There was a glitch in the system. Please contact the system administrator.") + } + + // Flush the user out of the cache and reload + err = users.Load(uid) + if err != nil { + return errors.New("Your account no longer exists!") + } + + return nil +} + +func (auth *DefaultAuth) Logout(w http.ResponseWriter, _ int) { + cookie := http.Cookie{Name:"uid",Value:"",Path:"/",MaxAge: year} + http.SetCookie(w,&cookie) + cookie = http.Cookie{Name:"session",Value:"",Path:"/",MaxAge: year} + http.SetCookie(w,&cookie) +} + +func (auth *DefaultAuth) SetCookies(w http.ResponseWriter, uid int, session string) { + cookie := http.Cookie{Name: "uid",Value: strconv.Itoa(uid),Path: "/",MaxAge: year} + http.SetCookie(w,&cookie) + cookie = http.Cookie{Name: "session",Value: session,Path: "/",MaxAge: year} + http.SetCookie(w,&cookie) +} + +func(auth *DefaultAuth) CreateSession(uid int) (string, error) { + session, err := GenerateSafeString(sessionLength) + if err != nil { + return "", err + } + + _, err = update_session_stmt.Exec(session, uid) + if err != nil { + return "", err + } + + // Reload the user data + _ = users.Load(uid) + return session, nil +} diff --git a/errors.go b/errors.go index 4cb5377d..a1421680 100644 --- a/errors.go +++ b/errors.go @@ -26,6 +26,10 @@ func init_errors() error { return nil } +func LogError(err error) { + log.Fatal(err) +} + func InternalError(err error, w http.ResponseWriter, r *http.Request) { w.Write(error_internal) log.Fatal(err) diff --git a/files.go b/files.go index dda32554..15f9ad3a 100644 --- a/files.go +++ b/files.go @@ -1,16 +1,17 @@ package main -import "log" -import "bytes" -import "strings" -import "mime" -//import "errors" -import "os" -//import "io" -import "io/ioutil" -import "path/filepath" -import "net/http" -import "compress/gzip" +import ( + "log" + "bytes" + "strings" + "mime" + //"errors" + "os" + "io/ioutil" + "path/filepath" + "net/http" + "compress/gzip" +) type SFile struct { @@ -24,42 +25,39 @@ type SFile struct FormattedModTime string } -/*func (r SFile) Read(b []byte) (n int, err error) { - n = 0 - if r.Pos > r.Length { - return n, io.EOF - } - - size := cap(b) - if size > 0 { - for n < size { - b[n] = r.Data[r.Pos] - n++ - if r.Pos == r.Length { - break - } - r.Pos++ - } - } - return n, nil +type CssData struct +{ + ComingSoon string } -func (r SFile) Seek(offset int64, whence int) (int64, error) { - if offset < 0 { - return 0, errors.New("negative position") +func init_static_files() { + log.Print("Loading the static files.") + err := filepath.Walk("./public", func(path string, f os.FileInfo, err error) error { + if f.IsDir() { + return nil + } + + path = strings.Replace(path,"\\","/",-1) + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + + path = strings.TrimPrefix(path,"public/") + var ext string = filepath.Ext("/public/" + path) + gzip_data := compress_bytes_gzip(data) + + static_files["/static/" + path] = SFile{data,gzip_data,0,int64(len(data)),int64(len(gzip_data)),mime.TypeByExtension(ext),f,f.ModTime().UTC().Format(http.TimeFormat)} + + if debug { + log.Print("Added the '" + path + "' static file.") + } + return nil + }) + if err != nil { + log.Fatal(err) } - switch whence { - case 0: - r.Pos = offset - case 1: - r.Pos += offset - case 2: - r.Pos = r.Length + offset - default: - return 0, errors.New("invalid whence") - } - return r.Pos, nil -}*/ +} func add_static_file(path string, prefix string) error { data, err := ioutil.ReadFile(path) @@ -74,20 +72,22 @@ func add_static_file(path string, prefix string) error { if err != nil { return err } - + + var ext string = filepath.Ext(path) path = strings.TrimPrefix(path, prefix) + gzip_data := compress_bytes_gzip(data) + + static_files["/static" + path] = SFile{data,gzip_data,0,int64(len(data)),int64(len(gzip_data)),mime.TypeByExtension(ext),f,f.ModTime().UTC().Format(http.TimeFormat)} + if debug { log.Print("Added the '" + path + "' static file") } - gzip_data := compress_bytes_gzip(data) - - static_files["/static" + path] = SFile{data,gzip_data,0,int64(len(data)),int64(len(gzip_data)),mime.TypeByExtension(filepath.Ext(prefix + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} return nil } func compress_bytes_gzip(in []byte) []byte { var buff bytes.Buffer - gz := gzip.NewWriter(&buff) + gz := gzip.NewWriter(&buff) gz.Write(in) gz.Close() return buff.Bytes() diff --git a/gen_mysql.go b/gen_mysql.go index cad0d5e7..59b8b59f 100644 --- a/gen_mysql.go +++ b/gen_mysql.go @@ -9,9 +9,7 @@ import "database/sql" var get_user_stmt *sql.Stmt var get_reply_stmt *sql.Stmt var get_user_reply_stmt *sql.Stmt -var login_stmt *sql.Stmt var get_password_stmt *sql.Stmt -var username_exists_stmt *sql.Stmt var get_settings_stmt *sql.Stmt var get_setting_stmt *sql.Stmt var get_full_setting_stmt *sql.Stmt @@ -56,7 +54,6 @@ var create_action_reply_stmt *sql.Stmt var create_like_stmt *sql.Stmt var add_activity_stmt *sql.Stmt var notify_one_stmt *sql.Stmt -var register_stmt *sql.Stmt var add_email_stmt *sql.Stmt var create_profile_reply_stmt *sql.Stmt var add_subscription_stmt *sql.Stmt @@ -81,7 +78,6 @@ var stick_topic_stmt *sql.Stmt var unstick_topic_stmt *sql.Stmt var update_last_ip_stmt *sql.Stmt var update_session_stmt *sql.Stmt -var logout_stmt *sql.Stmt var set_password_stmt *sql.Stmt var set_avatar_stmt *sql.Stmt var set_username_stmt *sql.Stmt @@ -111,6 +107,8 @@ var delete_profile_reply_stmt *sql.Stmt var delete_forum_perms_by_forum_stmt *sql.Stmt var report_exists_stmt *sql.Stmt var add_forum_perms_to_forum_admins_stmt *sql.Stmt +var add_forum_perms_to_forum_staff_stmt *sql.Stmt +var add_forum_perms_to_forum_members_stmt *sql.Stmt var notify_watchers_stmt *sql.Stmt func gen_mysql() (err error) { @@ -136,24 +134,12 @@ func gen_mysql() (err error) { return err } - log.Print("Preparing login statement.") - login_stmt, err = db.Prepare("SELECT `uid`,`name`,`password`,`salt` FROM `users` WHERE `name` = ?") - if err != nil { - return err - } - log.Print("Preparing get_password statement.") get_password_stmt, err = db.Prepare("SELECT `password`,`salt` FROM `users` WHERE `uid` = ?") if err != nil { return err } - log.Print("Preparing username_exists statement.") - username_exists_stmt, err = db.Prepare("SELECT `name` FROM `users` WHERE `name` = ?") - if err != nil { - return err - } - log.Print("Preparing get_settings statement.") get_settings_stmt, err = db.Prepare("SELECT `name`,`content`,`type` FROM `settings`") if err != nil { @@ -418,12 +404,6 @@ func gen_mysql() (err error) { return err } - log.Print("Preparing register statement.") - register_stmt, err = db.Prepare("INSERT INTO `users`(`name`,`email`,`password`,`salt`,`group`,`is_super_admin`,`session`,`active`,`message`) VALUES (?,?,?,?,?,0,?,?,'')") - if err != nil { - return err - } - log.Print("Preparing add_email statement.") add_email_stmt, err = db.Prepare("INSERT INTO `emails`(`email`,`uid`,`validated`,`token`) VALUES (?,?,?,?)") if err != nil { @@ -568,12 +548,6 @@ func gen_mysql() (err error) { return err } - log.Print("Preparing logout statement.") - logout_stmt, err = db.Prepare("UPDATE `users` SET `session` = '' WHERE `uid` = ?") - if err != nil { - return err - } - log.Print("Preparing set_password statement.") set_password_stmt, err = db.Prepare("UPDATE `users` SET `password` = ?,`salt` = ? WHERE `uid` = ?") if err != nil { @@ -748,6 +722,18 @@ func gen_mysql() (err error) { return err } + log.Print("Preparing add_forum_perms_to_forum_staff statement.") + add_forum_perms_to_forum_staff_stmt, err = db.Prepare("INSERT INTO `forums_permissions`(`gid`,`fid`,`preset`,`permissions`) SELECT `gid`, ? AS `fid`, ? AS `preset`, ? AS `permissions` FROM `users_groups` WHERE `is_admin` = 0 AND `is_mod` = 1") + if err != nil { + return err + } + + log.Print("Preparing add_forum_perms_to_forum_members statement.") + add_forum_perms_to_forum_members_stmt, err = db.Prepare("INSERT INTO `forums_permissions`(`gid`,`fid`,`preset`,`permissions`) SELECT `gid`, ? AS `fid`, ? AS `preset`, ? AS `permissions` FROM `users_groups` WHERE `is_admin` = 0 AND `is_mod` = 0 AND `is_banned` = 0") + if err != nil { + return err + } + log.Print("Preparing notify_watchers statement.") notify_watchers_stmt, err = db.Prepare("INSERT INTO `activity_stream_matches`(`watcher`,`asid`) SELECT `activity_subscriptions`.`user`, `activity_stream`.`asid` FROM `activity_stream` INNER JOIN `activity_subscriptions` ON `activity_subscriptions`.`targetType` = `activity_stream`.`elementType` AND `activity_subscriptions`.`targetID` = `activity_stream`.`elementID` AND `activity_subscriptions`.`user` != `activity_stream`.`actor` WHERE `asid` = ?") if err != nil { diff --git a/main.go b/main.go index b12bc378..8d0a069b 100644 --- a/main.go +++ b/main.go @@ -5,13 +5,8 @@ import ( "net/http" "fmt" "log" - "mime" "time" - "strings" - "path/filepath" "io" - "io/ioutil" - "os" "html/template" //"runtime/pprof" ) @@ -26,9 +21,6 @@ const kilobyte int = 1024 const megabyte int = kilobyte * 1024 const gigabyte int = megabyte * 1024 const terabyte int = gigabyte * 1024 -//const thousand int = 1000 -//const million int = 1_000_000 -//const billion int = 1_000_000_000 const saltLength int = 32 const sessionLength int = 80 var enable_websockets bool = false // Don't change this, the value is overwritten by an initialiser @@ -59,8 +51,8 @@ func compile_templates() { NoticeList:[]string{"test"}, Stylesheets:[]string{"panel"}, Scripts:[]string{"whatever"}, - Sidebars:HeaderSidebars{ - Left: template.HTML("lalala"), + Widgets:PageWidgets{ + LeftSidebar: template.HTML("lalala"), }, } @@ -142,33 +134,6 @@ func init_templates() { template.Must(templates.ParseGlob("pages/*")) } -func init_static_files() { - log.Print("Loading the static files.") - err := filepath.Walk("./public", func(path string, f os.FileInfo, err error) error { - if f.IsDir() { - return nil - } - - path = strings.Replace(path,"\\","/",-1) - data, err := ioutil.ReadFile(path) - if err != nil { - return err - } - - path = strings.TrimPrefix(path,"public/") - if debug { - log.Print("Added the '" + path + "' static file.") - } - gzip_data := compress_bytes_gzip(data) - - static_files["/static/" + path] = SFile{data,gzip_data,0,int64(len(data)),int64(len(gzip_data)),mime.TypeByExtension(filepath.Ext("/public/" + path)),f,f.ModTime().UTC().Format(http.TimeFormat)} - return nil - }) - if err != nil { - log.Fatal(err) - } -} - func main(){ //if profiling { // f, err := os.Create("startup_cpu.prof") @@ -215,6 +180,9 @@ func main(){ log.Fatal(err) } + log.Print("Initialising the authentication system") + auth = NewDefaultAuth() + log.Print("Initialising the router") router := NewGenRouter(http.FileServer(http.Dir("./uploads"))) ///router.HandleFunc("/static/", route_static) diff --git a/mysql.go b/mysql.go index 0e0a8d28..1893d3f7 100644 --- a/mysql.go +++ b/mysql.go @@ -9,9 +9,6 @@ import "./query_gen/lib" var get_activity_feed_by_watcher_stmt *sql.Stmt var get_activity_count_by_watcher_stmt *sql.Stmt -var add_forum_perms_to_forum_staff_stmt *sql.Stmt -var add_forum_perms_to_forum_members_stmt *sql.Stmt -var update_forum_perms_for_group_stmt *sql.Stmt var todays_post_count_stmt *sql.Stmt var todays_topic_count_stmt *sql.Stmt var todays_report_count_stmt *sql.Stmt @@ -65,18 +62,6 @@ func _init_database() (err error) { return err } - log.Print("Preparing add_forum_perms_to_forum_staff statement.") - add_forum_perms_to_forum_staff_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset,? AS permissions FROM users_groups WHERE is_admin = 0 AND is_mod = 1") - if err != nil { - return err - } - - log.Print("Preparing add_forum_perms_to_forum_members statement.") - add_forum_perms_to_forum_members_stmt, err = db.Prepare("INSERT INTO forums_permissions(gid,fid,preset,permissions) SELECT `gid`,? AS fid,? AS preset,? AS permissions FROM users_groups WHERE is_admin = 0 AND is_mod = 0 AND is_banned = 0") - if err != nil { - return err - } - log.Print("Preparing todays_post_count statement.") todays_post_count_stmt, err = db.Prepare("select count(*) from replies where createdAt BETWEEN (now() - interval 1 day) and now()") if err != nil { diff --git a/pages.go b/pages.go index 06faaf84..74b4034f 100644 --- a/pages.go +++ b/pages.go @@ -13,13 +13,13 @@ type HeaderVars struct NoticeList []string Scripts []string Stylesheets []string - Sidebars HeaderSidebars + Widgets PageWidgets } -type HeaderSidebars struct +type PageWidgets struct { - Left template.HTML - Right template.HTML + LeftSidebar template.HTML + RightSidebar template.HTML } type ExtData struct diff --git a/panel_routes.go b/panel_routes.go index 36f41c5d..45fa82d2 100644 --- a/panel_routes.go +++ b/panel_routes.go @@ -1466,6 +1466,7 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st } var isDefault bool + fmt.Println("uname",uname) err := is_theme_default_stmt.QueryRow(uname).Scan(&isDefault) if err != nil && err != sql.ErrNoRows { InternalError(err,w,r) @@ -1474,6 +1475,7 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st has_theme := err != sql.ErrNoRows if has_theme { + fmt.Println("isDefault",isDefault) if isDefault { LocalError("The theme is already active",w,r,user) return @@ -1511,7 +1513,7 @@ func route_panel_themes_default(w http.ResponseWriter, r *http.Request, uname st defaultTheme = uname reset_template_overrides() - add_theme_static_files(uname) + add_theme_static_files(themes[uname]) map_theme_templates(theme) http.Redirect(w,r,"/panel/themes/",http.StatusSeeOther) diff --git a/query_gen/lib/builder.go b/query_gen/lib/builder.go index a5f777ef..13d24bf0 100644 --- a/query_gen/lib/builder.go +++ b/query_gen/lib/builder.go @@ -64,6 +64,30 @@ func (build *builder) SimpleInsert(table string, columns string, fields string) return build.conn.Prepare(res) } +func (build *builder) SimpleInsertSelect(ins DB_Insert, sel DB_Select) (stmt *sql.Stmt, err error) { + res, err := build.adapter.SimpleInsertSelect("_builder", ins, sel) + if err != nil { + return stmt, err + } + return build.conn.Prepare(res) +} + +func (build *builder) SimpleInsertLeftJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) { + res, err := build.adapter.SimpleInsertLeftJoin("_builder", ins, sel) + if err != nil { + return stmt, err + } + return build.conn.Prepare(res) +} + +func (build *builder) SimpleInsertInnerJoin(ins DB_Insert, sel DB_Join) (stmt *sql.Stmt, err error) { + res, err := build.adapter.SimpleInsertInnerJoin("_builder", ins, sel) + if err != nil { + return stmt, err + } + return build.conn.Prepare(res) +} + func (build *builder) SimpleUpdate(table string, set string, where string) (stmt *sql.Stmt, err error) { res, err := build.adapter.SimpleUpdate("_builder", table, set, where) if err != nil { diff --git a/query_gen/lib/mysql.go b/query_gen/lib/mysql.go index 4dc8fc2e..c87a5e1a 100644 --- a/query_gen/lib/mysql.go +++ b/query_gen/lib/mysql.go @@ -452,6 +452,7 @@ func (adapter *Mysql_Adapter) SimpleInnerJoin(name string, table1 string, table2 func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel DB_Select) (string, error) { /* Insert Portion */ + var querystr string = "INSERT INTO `" + ins.Table + "`(" // Escape the column names, just in case we've used a reserved keyword @@ -523,8 +524,94 @@ func (adapter *Mysql_Adapter) SimpleInsertSelect(name string, ins DB_Insert, sel return querystr, nil } +func (adapter *Mysql_Adapter) SimpleInsertLeftJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { + /* Insert Portion */ + + var querystr string = "INSERT INTO `" + ins.Table + "`(" + + // Escape the column names, just in case we've used a reserved keyword + for _, column := range _process_columns(ins.Columns) { + if column.Type == "function" { + querystr += column.Left + "," + } else { + querystr += "`" + column.Left + "`," + } + } + querystr = querystr[0:len(querystr) - 1] + ") SELECT" + + /* Select Portion */ + + for _, column := range _process_columns(sel.Columns) { + var source, alias string + + // Escape the column names, just in case we've used a reserved keyword + if column.Table != "" { + source = "`" + column.Table + "`.`" + column.Left + "`" + } else if column.Type == "function" { + source = column.Left + } else { + source = "`" + column.Left + "`" + } + + if column.Alias != "" { + alias = " AS `" + column.Alias + "`" + } + querystr += " " + source + alias + "," + } + querystr = querystr[0:len(querystr) - 1] + + querystr += " FROM `" + sel.Table1 + "` LEFT JOIN `" + sel.Table2 + "` ON " + for _, joiner := range _process_joiner(sel.Joiners) { + querystr += "`" + joiner.LeftTable + "`.`" + joiner.LeftColumn + "` " + joiner.Operator + " `" + joiner.RightTable + "`.`" + joiner.RightColumn + "` AND " + } + querystr = querystr[0:len(querystr) - 4] + + // Add support for BETWEEN x.x + if len(sel.Where) != 0 { + querystr += " WHERE" + for _, loc := range _process_where(sel.Where) { + for _, token := range loc.Expr { + switch(token.Type) { + case "function","operator","number","substitute": + querystr += " " + token.Contents + "" + case "column": + halves := strings.Split(token.Contents,".") + if len(halves) == 2 { + querystr += " `" + halves[0] + "`.`" + halves[1] + "`" + } else { + querystr += " `" + token.Contents + "`" + } + case "string": + querystr += " '" + token.Contents + "'" + default: + panic("This token doesn't exist o_o") + } + } + querystr += " AND" + } + querystr = querystr[0:len(querystr) - 4] + } + + if len(sel.Orderby) != 0 { + querystr += " ORDER BY " + for _, column := range _process_orderby(sel.Orderby) { + querystr += column.Column + " " + strings.ToUpper(column.Order) + "," + } + querystr = querystr[0:len(querystr) - 1] + } + + if sel.Limit != "" { + querystr += " LIMIT " + sel.Limit + } + + querystr = strings.TrimSpace(querystr) + adapter.push_statement(name,querystr) + return querystr, nil +} + func (adapter *Mysql_Adapter) SimpleInsertInnerJoin(name string, ins DB_Insert, sel DB_Join) (string, error) { /* Insert Portion */ + var querystr string = "INSERT INTO `" + ins.Table + "`(" // Escape the column names, just in case we've used a reserved keyword diff --git a/query_gen/lib/querygen.go b/query_gen/lib/querygen.go index bdb070ea..55076651 100644 --- a/query_gen/lib/querygen.go +++ b/query_gen/lib/querygen.go @@ -33,24 +33,6 @@ type DB_Insert struct Fields string } -/*type DB_Select struct -{ - Name string - Table string - Columns []DB_Column - Where []DB_Where - Orderby []DB_Order - Limit DB_Limit -} - -type DB_Insert struct -{ - Name string - Table string - Columns []DB_Column - Fields []DB_Field -}*/ - type DB_Column struct { Table string @@ -111,6 +93,7 @@ type DB_Adapter interface { SimpleLeftJoin(string,string,string,string,string,string,string,string) (string, error) SimpleInnerJoin(string,string,string,string,string,string,string,string) (string, error) SimpleInsertSelect(string,DB_Insert,DB_Select) (string,error) + SimpleInsertLeftJoin(string,DB_Insert,DB_Join) (string,error) SimpleInsertInnerJoin(string,DB_Insert,DB_Join) (string,error) SimpleCount(string,string,string,string) (string, error) Write() error diff --git a/query_gen/main.go b/query_gen/main.go index 5f6a22f3..72500a43 100644 --- a/query_gen/main.go +++ b/query_gen/main.go @@ -81,12 +81,8 @@ func write_selects(adapter qgen.DB_Adapter) error { adapter.SimpleSelect("get_reply","replies","tid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress, likeCount","rid = ?","","") adapter.SimpleSelect("get_user_reply","users_replies","uid, content, createdBy, createdAt, lastEdit, lastEditBy, ipaddress","rid = ?","","") - - adapter.SimpleSelect("login","users","uid, name, password, salt","name = ?","","") - - adapter.SimpleSelect("get_password","users","password,salt","uid = ?","","") - adapter.SimpleSelect("username_exists","users","name","name = ?","","") + adapter.SimpleSelect("get_password","users","password,salt","uid = ?","","") adapter.SimpleSelect("get_settings","settings","name, content, type","","","") @@ -189,10 +185,6 @@ func write_inserts(adapter qgen.DB_Adapter) error { adapter.SimpleInsert("notify_one","activity_stream_matches","watcher,asid","?,?") - // Add an admin version of register_stmt with more flexibility? - // create_account_stmt, err = db.Prepare("INSERT INTO - adapter.SimpleInsert("register","users","name, email, password, salt, group, is_super_admin, session, active, message","?,?,?,?,?,0,?,?,''") - adapter.SimpleInsert("add_email","emails","email, uid, validated, token","?,?,?,?") adapter.SimpleInsert("create_profile_reply","users_replies","uid, content, parsed_content, createdAt, createdBy, ipaddress","?,?,?,NOW(),?,?") @@ -249,8 +241,6 @@ func write_updates(adapter qgen.DB_Adapter) error { adapter.SimpleUpdate("update_last_ip","users","last_ip = ?","uid = ?") adapter.SimpleUpdate("update_session","users","session = ?","uid = ?") - - adapter.SimpleUpdate("logout","users","session = ''","uid = ?") adapter.SimpleUpdate("set_password","users","password = ?, salt = ?","uid = ?") @@ -327,6 +317,16 @@ func write_insert_selects(adapter qgen.DB_Adapter) error { qgen.DB_Select{"users_groups","gid, ? AS fid, ? AS preset, ? AS permissions","is_admin = 1","",""}, ) + adapter.SimpleInsertSelect("add_forum_perms_to_forum_staff", + qgen.DB_Insert{"forums_permissions","gid,fid,preset,permissions",""}, + qgen.DB_Select{"users_groups","gid, ? AS fid, ? AS preset, ? AS permissions","is_admin = 0 AND is_mod = 1","",""}, + ) + + adapter.SimpleInsertSelect("add_forum_perms_to_forum_members", + qgen.DB_Insert{"forums_permissions","gid,fid,preset,permissions",""}, + qgen.DB_Select{"users_groups","gid, ? AS fid, ? AS preset, ? AS permissions","is_admin = 0 AND is_mod = 0 AND is_banned = 0","",""}, + ) + return nil } diff --git a/routes.go b/routes.go index 1a1166ce..8f02427e 100644 --- a/routes.go +++ b/routes.go @@ -190,7 +190,13 @@ func route_topics(w http.ResponseWriter, r *http.Request){ func route_forum(w http.ResponseWriter, r *http.Request, sfid string){ page, _ := strconv.Atoi(r.FormValue("page")) - fid, err := strconv.Atoi(sfid) + + // SEO URLs... + halves := strings.Split(sfid,".") + if len(halves) < 2 { + halves = append(halves,halves[0]) + } + fid, err := strconv.Atoi(halves[1]) if err != nil { PreError("The provided ForumID is not a valid number.",w,r) return @@ -1238,18 +1244,7 @@ func route_account_own_edit_critical_submit(w http.ResponseWriter, r *http.Reque SetPassword(user.ID, new_password) // Log the user out as a safety precaution - _, err = logout_stmt.Exec(user.ID) - if err != nil { - InternalError(err,w,r) - return - } - - // Reload the user data - err = users.Load(user.ID) - if err != nil { - LocalError("Your account no longer exists!",w,r,user) - return - } + auth.ForceLogout(user.ID) headerVars.NoticeList = append(headerVars.NoticeList,"Your password was successfully updated") pi := Page{"Edit Password",user,headerVars,tList,nil} @@ -1542,18 +1537,7 @@ func route_logout(w http.ResponseWriter, r *http.Request) { LocalError("You can't logout without logging in first.",w,r,user) return } - - _, err := logout_stmt.Exec(user.ID) - if err != nil { - InternalError(err,w,r) - return - } - - err = users.Load(user.ID) - if err != nil { - LocalError("Your account doesn't exist!",w,r,user) - return - } + auth.Logout(w, user.ID) http.Redirect(w,r, "/", http.StatusSeeOther) } @@ -1585,79 +1569,24 @@ func route_login_submit(w http.ResponseWriter, r *http.Request) { return } - var uid int - var real_password, salt, session string - username := html.EscapeString(r.PostFormValue("username")) - password := r.PostFormValue("password") - - err = login_stmt.QueryRow(username).Scan(&uid, &username, &real_password, &salt) - if err == sql.ErrNoRows { - LocalError("That username doesn't exist.",w,r,user) - return - } else if err != nil { - InternalError(err,w,r) + uid, err := auth.Authenticate(html.EscapeString(r.PostFormValue("username")), r.PostFormValue("password")) + if err != nil { + LocalError(err.Error(),w,r,user) return } - // Admin password reset mechanism... - if salt == "" { - if password != real_password { - LocalError("That's not the correct password.",w,r,user) - return - } - - // Re-encrypt the password - SetPassword(uid, real_password) - - // Fe-fetch the user data... - err = login_stmt.QueryRow(username).Scan(&uid, &username, &real_password, &salt) - if err == sql.ErrNoRows { - LocalError("That username doesn't exist anymore.",w,r,user) - return - } else if err != nil { + var session string + if user.Session == "" { + session, err = auth.CreateSession(uid) + if err != nil { InternalError(err,w,r) return } + } else { + session = user.Session } - password = password + salt - if err != nil { - InternalError(err,w,r) - return - } - - err = bcrypt.CompareHashAndPassword([]byte(real_password), []byte(password)) - if err == bcrypt.ErrMismatchedHashAndPassword { - LocalError("That's not the correct password.",w,r,user) - return - } else if err != nil { - InternalError(err,w,r) - return - } - - session, err = GenerateSafeString(sessionLength) - if err != nil { - InternalError(err,w,r) - return - } - - _, err = update_session_stmt.Exec(session, uid) - if err != nil { - InternalError(err,w,r) - return - } - - // Reload the user data - err = users.Load(uid) - if err != nil { - LocalError("Your account no longer exists!",w,r,user) - return - } - - cookie := http.Cookie{Name:"uid",Value:strconv.Itoa(uid),Path:"/",MaxAge:year} - http.SetCookie(w,&cookie) - cookie = http.Cookie{Name:"session",Value:session,Path:"/",MaxAge:year} - http.SetCookie(w,&cookie) + auth.SetCookies(w,uid,session) http.Redirect(w,r,"/",http.StatusSeeOther) } @@ -1726,34 +1655,6 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) { return } - // Is this username already taken..? - err = username_exists_stmt.QueryRow(username).Scan(&username) - if err != nil && err != sql.ErrNoRows { - InternalError(err,w,r) - return - } else if err != sql.ErrNoRows { - LocalError("This username isn't available. Try another.",w,r,user) - return - } - - salt, err := GenerateSafeString(saltLength) - if err != nil { - InternalError(err,w,r) - return - } - session, err := GenerateSafeString(sessionLength) - if err != nil { - InternalError(err,w,r) - return - } - - password = password + salt - hashed_password, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) - if err != nil { - InternalError(err,w,r) - return - } - var active, group int switch settings["activation_type"] { case 1: // Activate All @@ -1763,13 +1664,11 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) { group = activation_group } - res, err := register_stmt.Exec(username,email,string(hashed_password),salt,group,session,active) - if err != nil { - InternalError(err,w,r) + uid, err := users.CreateUser(username, password, email, group, active) + if err == err_account_exists { + LocalError("This username isn't available. Try another.",w,r,user) return - } - lastId, err := res.LastInsertId() - if err != nil { + } else if err != nil { InternalError(err,w,r) return } @@ -1781,7 +1680,7 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) { InternalError(err,w,r) return } - _, err = add_email_stmt.Exec(email, lastId, 0, token) + _, err = add_email_stmt.Exec(email, uid, 0, token) if err != nil { InternalError(err,w,r) return @@ -1793,11 +1692,14 @@ func route_register_submit(w http.ResponseWriter, r *http.Request) { } } - cookie := http.Cookie{Name: "uid",Value: strconv.FormatInt(lastId, 10),Path: "/",MaxAge: year} - http.SetCookie(w,&cookie) - cookie = http.Cookie{Name: "session",Value: session,Path: "/",MaxAge: year} - http.SetCookie(w,&cookie) - http.Redirect(w,r, "/", http.StatusSeeOther) + session, err := auth.CreateSession(uid) + if err != nil { + InternalError(err,w,r) + return + } + + auth.SetCookies(w,uid,session) + http.Redirect(w,r,"/",http.StatusSeeOther) } var phrase_login_alerts []byte = []byte(`{"msgs":[{"msg":"Login to see your alerts","path":"/accounts/login"}]}`) diff --git a/template_forum.go b/template_forum.go index 6db71038..433dd730 100644 --- a/template_forum.go +++ b/template_forum.go @@ -51,7 +51,7 @@ w.Write(menu_6) } w.Write(menu_7) w.Write(header_9) -if tmpl_forum_vars.Header.Sidebars.Right != "" { +if tmpl_forum_vars.Header.Widgets.RightSidebar != "" { w.Write(header_10) } w.Write(header_11) @@ -137,9 +137,9 @@ w.Write(forum_31) } w.Write(forum_32) w.Write(footer_0) -if tmpl_forum_vars.Header.Sidebars.Right != "" { +if tmpl_forum_vars.Header.Widgets.RightSidebar != "" { w.Write(footer_1) -w.Write([]byte(string(tmpl_forum_vars.Header.Sidebars.Right))) +w.Write([]byte(string(tmpl_forum_vars.Header.Widgets.RightSidebar))) w.Write(footer_2) } w.Write(footer_3) diff --git a/template_forums.go b/template_forums.go index 736b7a75..6fbccecc 100644 --- a/template_forums.go +++ b/template_forums.go @@ -51,7 +51,7 @@ w.Write(menu_6) } w.Write(menu_7) w.Write(header_9) -if tmpl_forums_vars.Header.Sidebars.Right != "" { +if tmpl_forums_vars.Header.Widgets.RightSidebar != "" { w.Write(header_10) } w.Write(header_11) @@ -110,9 +110,9 @@ w.Write(forums_20) } w.Write(forums_21) w.Write(footer_0) -if tmpl_forums_vars.Header.Sidebars.Right != "" { +if tmpl_forums_vars.Header.Widgets.RightSidebar != "" { w.Write(footer_1) -w.Write([]byte(string(tmpl_forums_vars.Header.Sidebars.Right))) +w.Write([]byte(string(tmpl_forums_vars.Header.Widgets.RightSidebar))) w.Write(footer_2) } w.Write(footer_3) diff --git a/template_profile.go b/template_profile.go index d60cf491..67caaab4 100644 --- a/template_profile.go +++ b/template_profile.go @@ -51,7 +51,7 @@ w.Write(menu_6) } w.Write(menu_7) w.Write(header_9) -if tmpl_profile_vars.Header.Sidebars.Right != "" { +if tmpl_profile_vars.Header.Widgets.RightSidebar != "" { w.Write(header_10) } w.Write(header_11) @@ -143,9 +143,9 @@ w.Write(profile_37) } w.Write(profile_38) w.Write(footer_0) -if tmpl_profile_vars.Header.Sidebars.Right != "" { +if tmpl_profile_vars.Header.Widgets.RightSidebar != "" { w.Write(footer_1) -w.Write([]byte(string(tmpl_profile_vars.Header.Sidebars.Right))) +w.Write([]byte(string(tmpl_profile_vars.Header.Widgets.RightSidebar))) w.Write(footer_2) } w.Write(footer_3) diff --git a/template_topic.go b/template_topic.go index 1fafae52..0b08f631 100644 --- a/template_topic.go +++ b/template_topic.go @@ -51,7 +51,7 @@ w.Write(menu_6) } w.Write(menu_7) w.Write(header_9) -if tmpl_topic_vars.Header.Sidebars.Right != "" { +if tmpl_topic_vars.Header.Widgets.RightSidebar != "" { w.Write(header_10) } w.Write(header_11) @@ -251,9 +251,9 @@ w.Write([]byte(strconv.Itoa(tmpl_topic_vars.Topic.ID))) w.Write(topic_83) } w.Write(footer_0) -if tmpl_topic_vars.Header.Sidebars.Right != "" { +if tmpl_topic_vars.Header.Widgets.RightSidebar != "" { w.Write(footer_1) -w.Write([]byte(string(tmpl_topic_vars.Header.Sidebars.Right))) +w.Write([]byte(string(tmpl_topic_vars.Header.Widgets.RightSidebar))) w.Write(footer_2) } w.Write(footer_3) diff --git a/template_topic_alt.go b/template_topic_alt.go index 5c64eacc..a8f212f3 100644 --- a/template_topic_alt.go +++ b/template_topic_alt.go @@ -51,7 +51,7 @@ w.Write(menu_6) } w.Write(menu_7) w.Write(header_9) -if tmpl_topic_alt_vars.Header.Sidebars.Right != "" { +if tmpl_topic_alt_vars.Header.Widgets.RightSidebar != "" { w.Write(header_10) } w.Write(header_11) @@ -257,9 +257,9 @@ w.Write([]byte(strconv.Itoa(tmpl_topic_alt_vars.Topic.ID))) w.Write(topic_alt_87) } w.Write(footer_0) -if tmpl_topic_alt_vars.Header.Sidebars.Right != "" { +if tmpl_topic_alt_vars.Header.Widgets.RightSidebar != "" { w.Write(footer_1) -w.Write([]byte(string(tmpl_topic_alt_vars.Header.Sidebars.Right))) +w.Write([]byte(string(tmpl_topic_alt_vars.Header.Widgets.RightSidebar))) w.Write(footer_2) } w.Write(footer_3) diff --git a/template_topics.go b/template_topics.go index 93794bd8..cb90bc38 100644 --- a/template_topics.go +++ b/template_topics.go @@ -51,7 +51,7 @@ w.Write(menu_6) } w.Write(menu_7) w.Write(header_9) -if tmpl_topics_vars.Header.Sidebars.Right != "" { +if tmpl_topics_vars.Header.Widgets.RightSidebar != "" { w.Write(header_10) } w.Write(header_11) @@ -113,9 +113,9 @@ w.Write(topics_21) } w.Write(topics_22) w.Write(footer_0) -if tmpl_topics_vars.Header.Sidebars.Right != "" { +if tmpl_topics_vars.Header.Widgets.RightSidebar != "" { w.Write(footer_1) -w.Write([]byte(string(tmpl_topics_vars.Header.Sidebars.Right))) +w.Write([]byte(string(tmpl_topics_vars.Header.Widgets.RightSidebar))) w.Write(footer_2) } w.Write(footer_3) diff --git a/templates.go b/templates.go index 6d672a3c..69f24d52 100644 --- a/templates.go +++ b/templates.go @@ -887,6 +887,9 @@ func (c *CTemplateSet) compile_varsub(varname string, val reflect.Value) string case reflect.Int64: return "w.Write([]byte(strconv.FormatInt(" + varname + ", 10)))" default: + if !val.IsValid() { + panic(varname + "^\n" + "Invalid value. Maybe, it doesn't exist?") + } fmt.Println("Unknown Variable Name:",varname) fmt.Println("Unknown Kind:",val.Kind()) fmt.Println("Unknown Type:",val.Type().Name()) diff --git a/templates/footer.html b/templates/footer.html index 0890b3d2..e612ed30 100644 --- a/templates/footer.html +++ b/templates/footer.html @@ -1,5 +1,5 @@ - {{if .Header.Sidebars.Right}}{{end}} + {{if .Header.Widgets.RightSidebar}}{{end}}
diff --git a/templates/header.html b/templates/header.html index 4ef90fe3..b008783a 100644 --- a/templates/header.html +++ b/templates/header.html @@ -18,5 +18,5 @@
{{template "menu.html" .}} -
+
{{range .Header.NoticeList}}
{{.}}
{{end}} diff --git a/templates/panel-themes.html b/templates/panel-themes.html index 3054dd85..0091c0c3 100644 --- a/templates/panel-themes.html +++ b/templates/panel-themes.html @@ -1,5 +1,15 @@ {{template "header.html" . }} -{{template "panel-menu.html" . }} +
+ +
+ +
+{{template "panel-inner-menu.html" . }} +
+ +