Merge pull request #252 from writeas/fix-mix-of-collations

Restrict /invite/{code} route to valid chars
This commit is contained in:
Matt Baer 2020-02-08 15:25:15 -05:00 committed by GitHub
commit 1a10bb3ed6
4 changed files with 29 additions and 4 deletions

View file

@ -1,7 +1,7 @@
// +build !sqlite,!wflib // +build !sqlite,!wflib
/* /*
* Copyright © 2019 A Bunch Tell LLC. * Copyright © 2019-2020 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -28,3 +28,15 @@ func (db *datastore) isDuplicateKeyErr(err error) bool {
return false return false
} }
func (db *datastore) isIgnorableError(err error) bool {
if db.driverName == driverMySQL {
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
return mysqlErr.Number == mySQLErrCollationMix
}
} else {
log.Error("isIgnorableError: failed check for unrecognized driver '%s'", db.driverName)
}
return false
}

View file

@ -48,3 +48,15 @@ func (db *datastore) isDuplicateKeyErr(err error) bool {
return false return false
} }
func (db *datastore) isIgnorableError(err error) bool {
if db.driverName == driverMySQL {
if mysqlErr, ok := err.(*mysql.MySQLError); ok {
return mysqlErr.Number == mySQLErrCollationMix
}
} else {
log.Error("isIgnorableError: failed check for unrecognized driver '%s'", db.driverName)
}
return false
}

View file

@ -1,5 +1,5 @@
/* /*
* Copyright © 2018 A Bunch Tell LLC. * Copyright © 2018-2020 A Bunch Tell LLC.
* *
* This file is part of WriteFreely. * This file is part of WriteFreely.
* *
@ -38,6 +38,7 @@ import (
const ( const (
mySQLErrDuplicateKey = 1062 mySQLErrDuplicateKey = 1062
mySQLErrCollationMix = 1267
driverMySQL = "mysql" driverMySQL = "mysql"
driverSQLite = "sqlite3" driverSQLite = "sqlite3"
@ -2328,7 +2329,7 @@ func (db *datastore) GetUserInvite(id string) (*Invite, error) {
var i Invite var i Invite
err := db.QueryRow("SELECT id, max_uses, created, expires, inactive FROM userinvites WHERE id = ?", id).Scan(&i.ID, &i.MaxUses, &i.Created, &i.Expires, &i.Inactive) err := db.QueryRow("SELECT id, max_uses, created, expires, inactive FROM userinvites WHERE id = ?", id).Scan(&i.ID, &i.MaxUses, &i.Created, &i.Expires, &i.Inactive)
switch { switch {
case err == sql.ErrNoRows: case err == sql.ErrNoRows, db.isIgnorableError(err):
return nil, impart.HTTPError{http.StatusNotFound, "Invite doesn't exist."} return nil, impart.HTTPError{http.StatusNotFound, "Invite doesn't exist."}
case err != nil: case err != nil:
log.Error("Failed selecting invite: %v", err) log.Error("Failed selecting invite: %v", err)

View file

@ -164,7 +164,7 @@ func InitRoutes(apper Apper, r *mux.Router) *mux.Router {
// Handle special pages first // Handle special pages first
write.HandleFunc("/login", handler.Web(viewLogin, UserLevelNoneRequired)) write.HandleFunc("/login", handler.Web(viewLogin, UserLevelNoneRequired))
write.HandleFunc("/signup", handler.Web(handleViewLanding, UserLevelNoneRequired)) write.HandleFunc("/signup", handler.Web(handleViewLanding, UserLevelNoneRequired))
write.HandleFunc("/invite/{code}", handler.Web(handleViewInvite, UserLevelOptional)).Methods("GET") write.HandleFunc("/invite/{code:[a-zA-Z0-9]+}", handler.Web(handleViewInvite, UserLevelOptional)).Methods("GET")
// TODO: show a reader-specific 404 page if the function is disabled // TODO: show a reader-specific 404 page if the function is disabled
write.HandleFunc("/read", handler.Web(viewLocalTimeline, UserLevelReader)) write.HandleFunc("/read", handler.Web(viewLocalTimeline, UserLevelReader))
RouteRead(handler, UserLevelReader, write.PathPrefix("/read").Subrouter()) RouteRead(handler, UserLevelReader, write.PathPrefix("/read").Subrouter())