restructure
This commit is contained in:
parent
443870dfaf
commit
e5cd04a91a
22
README.md
22
README.md
|
@ -1,4 +1,20 @@
|
||||||
# MapyWeb
|
# CokePlate
|
||||||
|
|
||||||
basic web panel/user system
|
|
||||||
|
|
||||||
|
boilerplate golang project
|
||||||
|
|
||||||
|
## features
|
||||||
|
|
||||||
|
* logging
|
||||||
|
- json
|
||||||
|
- pretty printing
|
||||||
|
|
||||||
|
* configuration
|
||||||
|
- toml
|
||||||
|
- write defaults if doesn't exist
|
||||||
|
|
||||||
|
* database
|
||||||
|
- dynamic (configurable) bitcask database initialization and access
|
||||||
|
|
||||||
|
* misc
|
||||||
|
- base64'd ascii/ansi banner defined in config
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
|
||||||
|
"mapyweb/config"
|
||||||
|
"mapyweb/db"
|
||||||
|
"mapyweb/extra"
|
||||||
|
)
|
||||||
|
|
||||||
|
var log zerolog.Logger
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
config.Init()
|
||||||
|
extra.Banner()
|
||||||
|
log = config.StartLogger()
|
||||||
|
log.Info().Msg("Starting databases...")
|
||||||
|
db.StartDatabases()
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,300 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Version roughly represents the applications current version.
|
||||||
|
Version = "0.2"
|
||||||
|
// Title is the name of the application used throughout the configuration process.
|
||||||
|
Title = "mapyweb"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// BannerOnly when toggled causes the appllication to only print the banner and version then exit.
|
||||||
|
BannerOnly = false
|
||||||
|
// GenConfig when toggled causes the application to write its default config to the cwd and then exit.
|
||||||
|
GenConfig = false
|
||||||
|
// NoColor when true will disable the banner and any colored console output.
|
||||||
|
NoColor bool
|
||||||
|
)
|
||||||
|
|
||||||
|
// "http"
|
||||||
|
var (
|
||||||
|
// HTTPBindAddr is defined via our toml configuration file. It is the address that the http server listens on.
|
||||||
|
HTTPBindAddr string
|
||||||
|
// HTTPBindPort is defined via our toml configuration file. It is the port that the http server listens on.
|
||||||
|
HTTPBindPort string
|
||||||
|
// UseUnixSocket when toggled disables the TCP listener and listens on the given UnixSocketPath.
|
||||||
|
UseUnixSocket bool
|
||||||
|
// UnixSocketPath is the path of the unix socket used when UseUnixSocket is toggled.
|
||||||
|
UnixSocketPath = ""
|
||||||
|
// HTTPUseSSL determins whether or not we serve HTTPs
|
||||||
|
HTTPUseSSL bool
|
||||||
|
// SSLCertFile is our fullchain SSL Certificate
|
||||||
|
SSLCertFile string
|
||||||
|
// SSLKeyFile is our SSL Certificate private key
|
||||||
|
SSLKeyFile string
|
||||||
|
)
|
||||||
|
|
||||||
|
// "db"
|
||||||
|
var (
|
||||||
|
UseEmbeddedPostgres bool
|
||||||
|
SQLHost string
|
||||||
|
SQLPort string
|
||||||
|
SQLUsername string
|
||||||
|
SQLPassword string
|
||||||
|
SQLDatabase string
|
||||||
|
DataPath string
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Filename returns the current location of our toml config file.
|
||||||
|
Filename string
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
f *os.File
|
||||||
|
err error
|
||||||
|
noColorForce = false
|
||||||
|
customconfig = false
|
||||||
|
home string
|
||||||
|
configLocations []string
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Debug is our global debug toggle
|
||||||
|
Debug bool
|
||||||
|
|
||||||
|
prefConfigLocation string
|
||||||
|
snek *viper.Viper
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
if home, err = os.UserHomeDir(); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
prefConfigLocation = home + "/.config/" + Title
|
||||||
|
snek = viper.New()
|
||||||
|
}
|
||||||
|
|
||||||
|
func writeConfig() {
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
if _, err := os.Stat(prefConfigLocation); os.IsNotExist(err) {
|
||||||
|
if err = os.Mkdir(prefConfigLocation, 0755); err != nil {
|
||||||
|
println("error writing new config: " + err.Error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newconfig := prefConfigLocation + "/" + "config.toml"
|
||||||
|
if err = snek.SafeWriteConfigAs(newconfig); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
Filename = newconfig
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
newconfig := Title
|
||||||
|
snek.SetConfigName(newconfig)
|
||||||
|
if err = snek.MergeInConfig(); err != nil {
|
||||||
|
if err = snek.SafeWriteConfigAs(newconfig + ".toml"); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Filename = newconfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init will initialize our toml configuration engine and define our default configuration values which can be written to a new configuration file if desired
|
||||||
|
func Init() {
|
||||||
|
snek.SetConfigType("toml")
|
||||||
|
snek.SetConfigName("config")
|
||||||
|
|
||||||
|
argParse()
|
||||||
|
|
||||||
|
if customconfig {
|
||||||
|
associate()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
acquireClue()
|
||||||
|
|
||||||
|
setDefaults()
|
||||||
|
|
||||||
|
for _, loc := range configLocations {
|
||||||
|
snek.AddConfigPath(loc)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = snek.MergeInConfig(); err != nil {
|
||||||
|
writeConfig()
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(Filename) < 1 {
|
||||||
|
Filename = snek.ConfigFileUsed()
|
||||||
|
}
|
||||||
|
|
||||||
|
associate()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setDefaults() {
|
||||||
|
var (
|
||||||
|
// Add new configuration categories here
|
||||||
|
configSections = []string{"logger", "http", "db"}
|
||||||
|
|
||||||
|
deflogdir = home + "/.config/" + Title + "/logs/"
|
||||||
|
defNoColor = false
|
||||||
|
)
|
||||||
|
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
deflogdir = "logs/"
|
||||||
|
defNoColor = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Opt := make(map[string]map[string]interface{})
|
||||||
|
|
||||||
|
Opt["logger"] = map[string]interface{}{
|
||||||
|
"debug": true,
|
||||||
|
"directory": deflogdir,
|
||||||
|
"nocolor": defNoColor,
|
||||||
|
"use_date_filename": true,
|
||||||
|
}
|
||||||
|
Opt["http"] = map[string]interface{}{
|
||||||
|
"use_unix_socket": false,
|
||||||
|
"unix_socket_path": "/var/run/cokeplate",
|
||||||
|
"bind_addr": "127.0.0.1",
|
||||||
|
"bind_port": "8080",
|
||||||
|
}
|
||||||
|
Opt["db"] = map[string]interface{}{
|
||||||
|
"embedded_pgsql": true,
|
||||||
|
"sql_host": "localhost",
|
||||||
|
"sql_port": "5432",
|
||||||
|
"sql_user": "postgres",
|
||||||
|
"sql_pass": "postgres",
|
||||||
|
"data_path": "./data",
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, def := range configSections {
|
||||||
|
snek.SetDefault(def, Opt[def])
|
||||||
|
}
|
||||||
|
|
||||||
|
if GenConfig {
|
||||||
|
if err = snek.SafeWriteConfigAs("./config.toml"); err != nil {
|
||||||
|
fmt.Println(err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func acquireClue() {
|
||||||
|
configLocations = append(configLocations, "./")
|
||||||
|
|
||||||
|
if runtime.GOOS != "windows" {
|
||||||
|
configLocations = append(configLocations, prefConfigLocation)
|
||||||
|
configLocations = append(configLocations, "/etc/"+Title+"/")
|
||||||
|
configLocations = append(configLocations, "../")
|
||||||
|
configLocations = append(configLocations, "../../")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadCustomConfig(path string) {
|
||||||
|
if f, err = os.Open(path); err != nil {
|
||||||
|
println("Error opening specified config file: " + path)
|
||||||
|
panic("config file open fatal error: " + err.Error())
|
||||||
|
}
|
||||||
|
buf, err := ioutil.ReadAll(f)
|
||||||
|
err2 := snek.ReadConfig(bytes.NewBuffer(buf))
|
||||||
|
switch {
|
||||||
|
case err != nil:
|
||||||
|
fmt.Println("config file read fatal error: ", err.Error())
|
||||||
|
case err2 != nil:
|
||||||
|
fmt.Println("config file read fatal error: ", err2.Error())
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
customconfig = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func printUsage() {
|
||||||
|
println("\n" + Title + " v" + Version + " Usage\n")
|
||||||
|
println("-c <config.toml> - Specify config file")
|
||||||
|
println("--nocolor - disable color and banner ")
|
||||||
|
println("--banner - show banner + version and exit")
|
||||||
|
println("--genconfig - write default config to 'default.toml' then exit")
|
||||||
|
os.Exit(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: should probably just make a proper CLI with flags or something
|
||||||
|
func argParse() {
|
||||||
|
for i, arg := range os.Args {
|
||||||
|
switch arg {
|
||||||
|
case "-h":
|
||||||
|
printUsage()
|
||||||
|
case "--genconfig":
|
||||||
|
GenConfig = true
|
||||||
|
case "--nocolor":
|
||||||
|
noColorForce = true
|
||||||
|
case "--banner":
|
||||||
|
BannerOnly = true
|
||||||
|
case "--config":
|
||||||
|
fallthrough
|
||||||
|
case "-c":
|
||||||
|
if len(os.Args) <= i-1 {
|
||||||
|
panic("syntax error! expected file after -c")
|
||||||
|
}
|
||||||
|
loadCustomConfig(os.Args[i+1])
|
||||||
|
default:
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func bl(key string) bool {
|
||||||
|
return snek.GetBool(key)
|
||||||
|
}
|
||||||
|
func st(key string) string {
|
||||||
|
return snek.GetString(key)
|
||||||
|
}
|
||||||
|
func sl(key string) []string {
|
||||||
|
return snek.GetStringSlice(key)
|
||||||
|
}
|
||||||
|
func it(key string) int {
|
||||||
|
return snek.GetInt(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func associate() {
|
||||||
|
HTTPBindAddr = st("http.bind_addr")
|
||||||
|
HTTPBindPort = st("http.bind_port")
|
||||||
|
UseUnixSocket = bl("http.use_unix_socket")
|
||||||
|
|
||||||
|
SQLPassword = st("db.sql_password")
|
||||||
|
SQLUsername = st("db.sql_username")
|
||||||
|
SQLDatabase = st("db.sql_database")
|
||||||
|
SQLHost = st("db.sql_host")
|
||||||
|
SQLPort = st("db.sql_port")
|
||||||
|
DataPath = st("db.data_path")
|
||||||
|
|
||||||
|
Debug = bl("logger.debug")
|
||||||
|
logDir = st("logger.directory")
|
||||||
|
NoColor = bl("logger.nocolor")
|
||||||
|
|
||||||
|
if noColorForce {
|
||||||
|
NoColor = true
|
||||||
|
}
|
||||||
|
// if UseUnixSocket {
|
||||||
|
// UnixSocketPath = snek.GetString("http.unix_socket_path")
|
||||||
|
// }
|
||||||
|
if Debug {
|
||||||
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
CurrentLogFile string
|
||||||
|
logFile *os.File
|
||||||
|
logDir string
|
||||||
|
logger zerolog.Logger
|
||||||
|
)
|
||||||
|
|
||||||
|
// StartLogger instantiates an instance of our zerolog loggger so we can hook it in our main package.
|
||||||
|
// While this does return a logger, it should not be used for additional retrievals of the logger. Use GetLogger()
|
||||||
|
func StartLogger() zerolog.Logger {
|
||||||
|
logDir = snek.GetString("logger.directory")
|
||||||
|
if err := os.MkdirAll(logDir, 0755); err != nil {
|
||||||
|
println("cannot create log directory: " + logDir + "(" + err.Error() + ")")
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
tnow := Title
|
||||||
|
|
||||||
|
if snek.GetBool("logger.use_date_filename") {
|
||||||
|
tnow = strings.Replace(time.Now().Format(time.RFC822), " ", "_", -1)
|
||||||
|
tnow = strings.Replace(tnow, ":", "-", -1)
|
||||||
|
}
|
||||||
|
|
||||||
|
CurrentLogFile = logDir + tnow + ".log"
|
||||||
|
|
||||||
|
if logFile, err = os.OpenFile(CurrentLogFile, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666); err != nil {
|
||||||
|
println("cannot create log file: " + err.Error())
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
multi := zerolog.MultiLevelWriter(zerolog.ConsoleWriter{NoColor: NoColor, Out: os.Stdout}, logFile)
|
||||||
|
logger = zerolog.New(multi).With().Timestamp().Logger()
|
||||||
|
return logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetLogger retrieves our global logger object
|
||||||
|
func GetLogger() zerolog.Logger {
|
||||||
|
// future logic here
|
||||||
|
return logger
|
||||||
|
}
|
59
db.go
59
db.go
|
@ -1,59 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"database/sql"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
jsoniter "github.com/json-iterator/go"
|
|
||||||
"git.tcp.direct/tcp.direct/bitcask-mirror"
|
|
||||||
)
|
|
||||||
|
|
||||||
/*
|
|
||||||
create table users (
|
|
||||||
id int not null auto_increment,
|
|
||||||
banExpireDate datetime(3),
|
|
||||||
banReason varchar(255),
|
|
||||||
offensemanager int,
|
|
||||||
votepoints int default 0,
|
|
||||||
donationpoints int default 0,
|
|
||||||
maplePoints int default 0,
|
|
||||||
nxPrepaid int default 0,
|
|
||||||
name varchar(255),
|
|
||||||
password varchar(255),
|
|
||||||
pic varchar(255),
|
|
||||||
mac varchar(255),
|
|
||||||
accounttype int default 0,
|
|
||||||
age int default 0,
|
|
||||||
vipgrade int default 0,
|
|
||||||
nblockreason int default 0,
|
|
||||||
gender tinyint default 0,
|
|
||||||
msg2 tinyint default 0,
|
|
||||||
purchaseexp tinyint default 0,
|
|
||||||
pblockreason tinyint default 3,
|
|
||||||
chatunblockdate bigint default 0,
|
|
||||||
hascensorednxloginid boolean default 0,
|
|
||||||
gradecode tinyint default 0,
|
|
||||||
censorednxloginid varchar(255),
|
|
||||||
characterslots int default 4,
|
|
||||||
creationdate datetime(3),
|
|
||||||
primary key (id),
|
|
||||||
foreign key (offensemanager) references offense_managers(id)
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
// Credentials is the json structure for user data
|
|
||||||
type Credentials struct {
|
|
||||||
Password string `json:"password"`
|
|
||||||
Username string `json:"username"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
func initDB() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func rowExists(query string, args ...interface{}) bool {
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,8 +1,7 @@
|
||||||
package main
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pgsql "github.com/fergusstrange/embedded-postgres"
|
pgsql "github.com/fergusstrange/embedded-postgres"
|
||||||
|
@ -37,6 +36,24 @@ func getUser(username string) (u *User, err error) {
|
||||||
return u, nil
|
return u, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UserExists queries our database for a user using the given username and returns true if it exists, false if it does not.
|
||||||
|
func UserExists(username string) bool {
|
||||||
|
u := new(User)
|
||||||
|
if err := db.Get(u, "SELECT id FROM accounts WHERE username=$1", username); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// EmailTaken queries our database for a user using the given email address and returns true if the email is taken, false if it is not.
|
||||||
|
func EmailTaken(email string) bool {
|
||||||
|
u := new(User)
|
||||||
|
if err := db.Get(u, "SELECT id FROM accounts WHERE email=$1", email); err == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// AttemptWebLogin checks the given credentials for validity and returns a User and an error.
|
// AttemptWebLogin checks the given credentials for validity and returns a User and an error.
|
||||||
func AttemptWebLogin(username, password, ipaddr, useragent string) (*User, error) {
|
func AttemptWebLogin(username, password, ipaddr, useragent string) (*User, error) {
|
||||||
var (
|
var (
|
||||||
|
@ -44,21 +61,22 @@ func AttemptWebLogin(username, password, ipaddr, useragent string) (*User, error
|
||||||
err error
|
err error
|
||||||
good = false
|
good = false
|
||||||
)
|
)
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
|
// TODO: make bitcask max value size larger because this 000 is gonna get huge
|
||||||
// to log invalid users
|
// to log invalid users
|
||||||
if u == nil {
|
if u == nil {
|
||||||
u = &User{ID: 000}
|
u = &User{ID: 000}
|
||||||
}
|
}
|
||||||
if err := authlog.NewAttempt(int(u.ID), ipaddr, useragent, Web, good); err != nil {
|
if err := authlog.newAttempt(int(u.ID), ipaddr, useragent, Web, good); err != nil {
|
||||||
println(err.Error())
|
println(err.Error())
|
||||||
log.Error().Err(err).Msg("failed_login")
|
log.Error().Err(err).Msg("failed_login")
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
if u, err = getUser(username); err != nil {
|
if u, err = getUser(username); err != nil {
|
||||||
return u, err
|
return u, err
|
||||||
}
|
}
|
||||||
println("provided: ", password)
|
|
||||||
println("hashed: ", u.Password)
|
|
||||||
if !CheckPasswordHash(password, u.Password) {
|
if !CheckPasswordHash(password, u.Password) {
|
||||||
return nil, errors.New("invalid password")
|
return nil, errors.New("invalid password")
|
||||||
}
|
}
|
||||||
|
@ -91,37 +109,5 @@ func RegisterNewUser(username, password, ipaddr string, gender int, admin bool)
|
||||||
}
|
}
|
||||||
_, err = db.NamedExec(`INSERT INTO accounts (username, password, creation, last_login, last_ip, ban, admin, gender)
|
_, err = db.NamedExec(`INSERT INTO accounts (username, password, creation, last_login, last_ip, ban, admin, gender)
|
||||||
VALUES (:username, :password, :creation, :last_login, :last_ip, 0, :admin, :gender);`, u)
|
VALUES (:username, :password, :creation, :last_login, :last_ip, 0, :admin, :gender);`, u)
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
|
||||||
var err error
|
|
||||||
postgres = pgsql.NewDatabase(pgsql.DefaultConfig().
|
|
||||||
DataPath("./data/pgsql").
|
|
||||||
BinariesPath("./postgresql").
|
|
||||||
Logger(os.Stdout))
|
|
||||||
if err := postgres.Start(); err != nil {
|
|
||||||
log.Error().Err(err).Msg("postgres_fail")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer postgres.Stop()
|
|
||||||
|
|
||||||
if authlog, err = GetUserAuths("./data/authlog"); err != nil {
|
|
||||||
log.Error().Caller().Err(err).Msg("!!! GetUserAuths failed !!!")
|
|
||||||
}
|
|
||||||
|
|
||||||
db, err = sqlx.Connect("postgres",
|
|
||||||
"host=localhost port=5432 user=postgres password=postgres dbname=postgres sslmode=disable")
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Error().Caller().Err(err).Msg("postgres_fail")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
Banner()
|
|
||||||
|
|
||||||
argParse()
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package db
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
@ -8,10 +8,10 @@ import (
|
||||||
"git.tcp.direct/tcp.direct/bitcask-mirror"
|
"git.tcp.direct/tcp.direct/bitcask-mirror"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthLog is for implementing an authentication log
|
// AuthLog is for implementing an authentication log.
|
||||||
type AuthLog interface {
|
type AuthLog interface {
|
||||||
NewAttempt(id int, ip, useragent string, source AuthSource, good bool) error
|
newAttempt(id int, ip, useragent string, source AuthSource, good bool) error
|
||||||
GetLog(id int) (map[time.Time]AuthAttempt, error)
|
getLog(id int) (map[time.Time]AuthAttempt, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthSource uint32
|
type AuthSource uint32
|
||||||
|
@ -21,7 +21,7 @@ const (
|
||||||
Client // 1
|
Client // 1
|
||||||
)
|
)
|
||||||
|
|
||||||
// AuthAttempt represents a login attempt, used for our authlog
|
// AuthAttempt represents a login attempt, used for our AuthLog.
|
||||||
type AuthAttempt struct {
|
type AuthAttempt struct {
|
||||||
Time time.Time
|
Time time.Time
|
||||||
IP string
|
IP string
|
||||||
|
@ -30,18 +30,18 @@ type AuthAttempt struct {
|
||||||
Good bool
|
Good bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// SecurityLog is an implementation of AuthLog
|
// secLog is an implementation of AuthLog
|
||||||
type SecurityLog struct {
|
type secLog struct {
|
||||||
DB *bitcask.Bitcask
|
DB *bitcask.Bitcask
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetUserAuths opens a bitcask database at path or starts a new one, then returns a SecurityLog and an error.
|
// GetUserAuths opens a bitcask database at path or starts a new one, then returns a secLog and an error.
|
||||||
func GetUserAuths(path string) (*SecurityLog, error) {
|
func GetUserAuths(path string) (*secLog, error) {
|
||||||
casket, err := bitcask.Open(path)
|
casket, err := bitcask.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &SecurityLog{DB: casket}, nil
|
return &secLog{DB: casket}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func idToUbytes(id int) []byte {
|
func idToUbytes(id int) []byte {
|
||||||
|
@ -51,7 +51,7 @@ func idToUbytes(id int) []byte {
|
||||||
return buf
|
return buf
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SecurityLog) GetLog(id int) (map[time.Time]AuthAttempt, error) {
|
func (s *secLog) getLog(id int) (map[time.Time]AuthAttempt, error) {
|
||||||
uidb := idToUbytes(id)
|
uidb := idToUbytes(id)
|
||||||
var logMap = make(map[time.Time]AuthAttempt)
|
var logMap = make(map[time.Time]AuthAttempt)
|
||||||
if !s.DB.Has(uidb) {
|
if !s.DB.Has(uidb) {
|
||||||
|
@ -68,10 +68,10 @@ func (s *SecurityLog) GetLog(id int) (map[time.Time]AuthAttempt, error) {
|
||||||
return logMap, nil
|
return logMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SecurityLog) NewAttempt(id int, ip, useragent string, source AuthSource, good bool) error {
|
func (s *secLog) newAttempt(id int, ip, useragent string, source AuthSource, good bool) error {
|
||||||
uidb := idToUbytes(id)
|
uidb := idToUbytes(id)
|
||||||
|
|
||||||
current, err := s.GetLog(id)
|
current, err := s.getLog(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,8 @@ func (s *SecurityLog) NewAttempt(id int, ip, useragent string, source AuthSource
|
||||||
current[time.Now()] = AuthAttempt{
|
current[time.Now()] = AuthAttempt{
|
||||||
Time: time.Now(),
|
Time: time.Now(),
|
||||||
IP: ip,
|
IP: ip,
|
||||||
UserAgent: useragent,
|
|
||||||
Source: source,
|
Source: source,
|
||||||
|
UserAgent: useragent,
|
||||||
Good: good,
|
Good: good,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package db
|
||||||
|
|
||||||
import "golang.org/x/crypto/bcrypt"
|
import "golang.org/x/crypto/bcrypt"
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
pgsql "github.com/fergusstrange/embedded-postgres"
|
||||||
|
"github.com/jmoiron/sqlx"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
|
"mapyweb/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
var accountsSchema = `create table accounts
|
||||||
|
(
|
||||||
|
id serial
|
||||||
|
constraint accounts_pkey
|
||||||
|
primary key,
|
||||||
|
username varchar(13) not null,
|
||||||
|
password varchar not null,
|
||||||
|
creation date not null,
|
||||||
|
last_login date not null,
|
||||||
|
last_ip varchar not null,
|
||||||
|
ban integer not null,
|
||||||
|
admin integer not null,
|
||||||
|
gender smallint default 0 not null
|
||||||
|
);`
|
||||||
|
|
||||||
|
var authlog *secLog
|
||||||
|
|
||||||
|
func install(db *sqlx.DB) {
|
||||||
|
if _, err := db.Exec(accountsSchema); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
println("accounts table installed!")
|
||||||
|
}
|
||||||
|
|
||||||
|
func loginTest() {
|
||||||
|
var kayos *User
|
||||||
|
var err error
|
||||||
|
println("logging in as kayos...")
|
||||||
|
if kayos, err = AttemptWebLogin(
|
||||||
|
"kayos",
|
||||||
|
"yeet",
|
||||||
|
"192.168.69.5",
|
||||||
|
"yeetBrowser 420"); err != nil {
|
||||||
|
println("FAIL: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println("logged in as kayos!")
|
||||||
|
println(kayos.Password)
|
||||||
|
}
|
||||||
|
|
||||||
|
func registerTest() {
|
||||||
|
println("registering kayos...")
|
||||||
|
if err := RegisterNewUser("kayos", "yeet", "127.0.0.1", 0, true); err != nil {
|
||||||
|
println("REG_TEST_FAIL: " + err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
println("kayos registered!")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func argParse() {
|
||||||
|
for _, arg := range os.Args {
|
||||||
|
if arg == "--install" {
|
||||||
|
println("installing...")
|
||||||
|
install(db)
|
||||||
|
}
|
||||||
|
if arg == "--regtest" {
|
||||||
|
registerTest()
|
||||||
|
}
|
||||||
|
if arg == "--logintest" {
|
||||||
|
loginTest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// StartDatabases initializes our embeded postgresql database and our embeded bitcask database.
|
||||||
|
func StartDatabases() {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// embedded postgres -
|
||||||
|
if config.UseEmbeddedPostgres {
|
||||||
|
postgres = pgsql.NewDatabase(pgsql.DefaultConfig().
|
||||||
|
DataPath("./data/pgsql").
|
||||||
|
BinariesPath("./postgresql").
|
||||||
|
Logger(os.Stdout))
|
||||||
|
if err := postgres.Start(); err != nil {
|
||||||
|
log.Error().Err(err).Msg("postgres_fail")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer postgres.Stop()
|
||||||
|
|
||||||
|
db, err = sqlx.Connect("postgres",
|
||||||
|
"host=localhost port=5432 user=postgres password=postgres dbname=postgres sslmode=disable")
|
||||||
|
} else {
|
||||||
|
connstr := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=disable", config.SQLHost, config.SQLPort, config.SQLUsername, config.SQLPassword)
|
||||||
|
db, err = sqlx.Connect("postgres", connstr)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Error().Caller().Err(err).Msg("postgres_fail")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
// embedded bitcask for authlog
|
||||||
|
if authlog, err = GetUserAuths("./data/authlog"); err != nil {
|
||||||
|
log.Error().Caller().Err(err).Msg("!!! GetUserAuths failed !!!")
|
||||||
|
}
|
||||||
|
// -------------------
|
||||||
|
|
||||||
|
argParse()
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package extra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
21
go.mod
21
go.mod
|
@ -9,12 +9,13 @@ require (
|
||||||
github.com/gorilla/csrf v1.7.1
|
github.com/gorilla/csrf v1.7.1
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
github.com/jmoiron/sqlx v1.3.4
|
github.com/jmoiron/sqlx v1.3.4
|
||||||
github.com/json-iterator/go v1.1.12
|
|
||||||
github.com/lib/pq v1.10.2
|
github.com/lib/pq v1.10.2
|
||||||
github.com/matcornic/hermes/v2 v2.1.0
|
github.com/matcornic/hermes/v2 v2.1.0
|
||||||
github.com/rs/zerolog v1.25.0
|
github.com/rs/zerolog v1.25.0
|
||||||
github.com/satori/go.uuid v1.2.0
|
github.com/satori/go.uuid v1.2.0
|
||||||
|
github.com/savsgio/atreugo/v11 v11.8.3
|
||||||
github.com/spf13/viper v1.8.1
|
github.com/spf13/viper v1.8.1
|
||||||
|
github.com/valyala/fasthttp v1.30.0
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -23,28 +24,27 @@ require (
|
||||||
github.com/Masterminds/sprig v2.16.0+incompatible // indirect
|
github.com/Masterminds/sprig v2.16.0+incompatible // indirect
|
||||||
github.com/PuerkitoBio/goquery v1.5.0 // indirect
|
github.com/PuerkitoBio/goquery v1.5.0 // indirect
|
||||||
github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81 // indirect
|
github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81 // indirect
|
||||||
github.com/andybalholm/brotli v1.0.0 // indirect
|
github.com/andybalholm/brotli v1.0.2 // indirect
|
||||||
github.com/andybalholm/cascadia v1.0.0 // indirect
|
github.com/andybalholm/cascadia v1.0.0 // indirect
|
||||||
github.com/aokoli/goutils v1.0.1 // indirect
|
github.com/aokoli/goutils v1.0.1 // indirect
|
||||||
github.com/dsnet/compress v0.0.1 // indirect
|
github.com/dsnet/compress v0.0.1 // indirect
|
||||||
|
github.com/fasthttp/router v1.4.3 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
github.com/gofrs/flock v0.8.0 // indirect
|
github.com/gofrs/flock v0.8.0 // indirect
|
||||||
github.com/golang/snappy v0.0.1 // indirect
|
github.com/golang/snappy v0.0.3 // indirect
|
||||||
github.com/google/uuid v1.1.2 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/gorilla/css v1.0.0 // indirect
|
github.com/gorilla/css v1.0.0 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||||
github.com/huandu/xstrings v1.2.0 // indirect
|
github.com/huandu/xstrings v1.2.0 // indirect
|
||||||
github.com/imdario/mergo v0.3.6 // indirect
|
github.com/imdario/mergo v0.3.6 // indirect
|
||||||
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 // indirect
|
github.com/jaytaylor/html2text v0.0.0-20180606194806-57d518f124b0 // indirect
|
||||||
github.com/klauspost/compress v1.10.10 // indirect
|
github.com/klauspost/compress v1.13.4 // indirect
|
||||||
github.com/klauspost/pgzip v1.2.4 // indirect
|
github.com/klauspost/pgzip v1.2.4 // indirect
|
||||||
github.com/magiconair/properties v1.8.5 // indirect
|
github.com/magiconair/properties v1.8.5 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.3 // indirect
|
github.com/mattn/go-runewidth v0.0.3 // indirect
|
||||||
github.com/mholt/archiver/v3 v3.5.0 // indirect
|
github.com/mholt/archiver/v3 v3.5.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
|
||||||
github.com/nwaples/rardecode v1.1.0 // indirect
|
github.com/nwaples/rardecode v1.1.0 // indirect
|
||||||
github.com/olekukonko/tablewriter v0.0.1 // indirect
|
github.com/olekukonko/tablewriter v0.0.1 // indirect
|
||||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||||
|
@ -52,6 +52,7 @@ require (
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/plar/go-adaptive-radix-tree v1.0.4 // indirect
|
github.com/plar/go-adaptive-radix-tree v1.0.4 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||||
|
github.com/savsgio/gotils v0.0.0-20210907153846-c06938798b52 // indirect
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/spf13/afero v1.6.0 // indirect
|
github.com/spf13/afero v1.6.0 // indirect
|
||||||
|
@ -61,13 +62,15 @@ require (
|
||||||
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
|
||||||
github.com/subosito/gotenv v1.2.0 // indirect
|
github.com/subosito/gotenv v1.2.0 // indirect
|
||||||
github.com/ulikunitz/xz v0.5.7 // indirect
|
github.com/ulikunitz/xz v0.5.7 // indirect
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
|
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||||
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 // indirect
|
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 // indirect
|
||||||
github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe // indirect
|
github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe // indirect
|
||||||
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
|
||||||
golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85 // indirect
|
golang.org/x/exp v0.0.0-20200228211341-fcea875c7e85 // indirect
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed // indirect
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 // indirect
|
||||||
golang.org/x/text v0.3.5 // indirect
|
golang.org/x/text v0.3.6 // indirect
|
||||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
40
go.sum
40
go.sum
|
@ -52,8 +52,9 @@ github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81 h1:uHogIJ9bXH75ZYrXnVShH
|
||||||
github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81/go.mod h1:6ZvnjTZX1LNo1oLpfaJK8h+MXqHxcBFBIwkgsv+xlv0=
|
github.com/abcum/lcp v0.0.0-20201209214815-7a3f3840be81/go.mod h1:6ZvnjTZX1LNo1oLpfaJK8h+MXqHxcBFBIwkgsv+xlv0=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
|
||||||
github.com/andybalholm/brotli v1.0.0 h1:7UCwP93aiSfvWpapti8g88vVVGp2qqtGyePsSuDafo4=
|
|
||||||
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
|
github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
|
||||||
|
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
|
||||||
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
|
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
|
||||||
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
||||||
|
@ -63,6 +64,8 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC
|
||||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||||
|
github.com/atreugo/mock v0.0.0-20200601091009-13c275b330b0 h1:IVqe9WnancrkICl5HqEfGjrnkQ4+VsU5fodcuFVoG/A=
|
||||||
|
github.com/atreugo/mock v0.0.0-20200601091009-13c275b330b0/go.mod h1:HTHAc8RoZXMVTr6wZQN7Jjm3mYMnbfkqqKdnQgSoe9o=
|
||||||
github.com/badoux/checkmail v1.2.1 h1:TzwYx5pnsV6anJweMx2auXdekBwGr/yt1GgalIx9nBQ=
|
github.com/badoux/checkmail v1.2.1 h1:TzwYx5pnsV6anJweMx2auXdekBwGr/yt1GgalIx9nBQ=
|
||||||
github.com/badoux/checkmail v1.2.1/go.mod h1:XroCOBU5zzZJcLvgwU15I+2xXyCdTWXyR9MGfRhBYy0=
|
github.com/badoux/checkmail v1.2.1/go.mod h1:XroCOBU5zzZJcLvgwU15I+2xXyCdTWXyR9MGfRhBYy0=
|
||||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||||
|
@ -101,6 +104,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
|
github.com/fasthttp/router v1.4.3 h1:spS+LUnRryQ/+hbmYzs/xWGJlQCkeQI3hxGZdlVYhLU=
|
||||||
|
github.com/fasthttp/router v1.4.3/go.mod h1:9ytWCfZ5LcCcbD3S7pEXyBX9vZnOZmN918WiiaYUzr8=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/fergusstrange/embedded-postgres v1.10.0 h1:YnwF6xAQYmKLAXXrrRx4rHDLih47YJwVPvg8jeKfdNg=
|
github.com/fergusstrange/embedded-postgres v1.10.0 h1:YnwF6xAQYmKLAXXrrRx4rHDLih47YJwVPvg8jeKfdNg=
|
||||||
github.com/fergusstrange/embedded-postgres v1.10.0/go.mod h1:a008U8/Rws5FtIOTGYDYa7beVWsT3qVKyqExqYYjL+c=
|
github.com/fergusstrange/embedded-postgres v1.10.0/go.mod h1:a008U8/Rws5FtIOTGYDYa7beVWsT3qVKyqExqYYjL+c=
|
||||||
|
@ -154,8 +159,9 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
|
github.com/golang/snappy v0.0.3 h1:fHPg5GQYlCeLIPB9BZqMVR5nR9A+IM5zcgeTdjMYmLA=
|
||||||
|
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
@ -186,8 +192,9 @@ github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLe
|
||||||
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||||
|
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
|
@ -240,8 +247,6 @@ github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
|
||||||
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
|
||||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||||
|
@ -251,8 +256,9 @@ github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvW
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.10.10 h1:a/y8CglcM7gLGYmlbP/stPE5sR3hbhFRUjCBfd/0B3I=
|
|
||||||
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
github.com/klauspost/compress v1.10.10/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
|
||||||
|
github.com/klauspost/compress v1.13.4 h1:0zhec2I8zGnjWcKyLl6i3gPqKANCCn5e9xmviEEeX6s=
|
||||||
|
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||||
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||||
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
|
github.com/klauspost/pgzip v1.2.4 h1:TQ7CNpYKovDOmqzRHKxJh0BeaBI7UdQZYc6p7pMQh1A=
|
||||||
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
github.com/klauspost/pgzip v1.2.4/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
|
||||||
|
@ -293,12 +299,9 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
|
||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
|
||||||
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
|
||||||
|
@ -342,6 +345,10 @@ github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
|
||||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||||
|
github.com/savsgio/atreugo/v11 v11.8.3 h1:5w9H7sBwJ4/MOYms3zZ3NRDPIyp2TBkhZ0GrerNGizA=
|
||||||
|
github.com/savsgio/atreugo/v11 v11.8.3/go.mod h1:d/+jyq8I/QyaWJvdGjvvvqVoG1gnqqjAg/hhSvnZloA=
|
||||||
|
github.com/savsgio/gotils v0.0.0-20210907153846-c06938798b52 h1:FODZE/jDkENIpW3JiMA9sXBQfNklTfClUNhR9k37dPY=
|
||||||
|
github.com/savsgio/gotils v0.0.0-20210907153846-c06938798b52/go.mod h1:oejLrk1Y/5zOF+c/aHtXqn3TFlzzbAgPWg8zBiAHDas=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
|
@ -394,6 +401,12 @@ github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGr
|
||||||
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
github.com/ulikunitz/xz v0.5.6/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
|
||||||
github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
|
github.com/ulikunitz/xz v0.5.7 h1:YvTNdFzX6+W5m9msiYg/zpkSURPPtOlzbqYjrFn7Yt4=
|
||||||
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
github.com/ulikunitz/xz v0.5.7/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
|
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||||
|
github.com/valyala/fasthttp v1.30.0 h1:nBNzWrgZUUHohyLPU/jTvXdhrcaf2m5k3bWk+3Q049g=
|
||||||
|
github.com/valyala/fasthttp v1.30.0/go.mod h1:2rsYD01CKFrjjsvFxx75KlEUNpWNBY9JWD3K/7o2Cus=
|
||||||
|
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||||
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 h1:L0rPdfzq43+NV8rfIx2kA4iSSLRj2jN5ijYHoeXRwvQ=
|
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04 h1:L0rPdfzq43+NV8rfIx2kA4iSSLRj2jN5ijYHoeXRwvQ=
|
||||||
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04/go.mod h1:tcnB1voG49QhCrwq1W0w5hhGasvOg+VQp9i9H1rCM1w=
|
github.com/vanng822/css v0.0.0-20190504095207-a21e860bcd04/go.mod h1:tcnB1voG49QhCrwq1W0w5hhGasvOg+VQp9i9H1rCM1w=
|
||||||
github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe h1:9YnI5plmy+ad6BM+JCLJb2ZV7/TNiE5l7SNKfumYKgc=
|
github.com/vanng822/go-premailer v0.0.0-20191214114701-be27abe028fe h1:9YnI5plmy+ad6BM+JCLJb2ZV7/TNiE5l7SNKfumYKgc=
|
||||||
|
@ -433,6 +446,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U
|
||||||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
|
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ=
|
||||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
|
@ -511,8 +525,9 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed h1:p9UgmWI9wKpfYmgaV/IZKGdXc5qEK45tDwwwDyjS26I=
|
||||||
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -581,7 +596,9 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
@ -591,8 +608,9 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|
218
main.go
218
main.go
|
@ -1,50 +1,77 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"database/sql"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"html/template"
|
"html/template"
|
||||||
"log"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/valyala/fasthttp"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/badoux/checkmail"
|
"github.com/badoux/checkmail"
|
||||||
"github.com/gorilla/csrf"
|
"github.com/gorilla/csrf"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
_ "github.com/lib/pq"
|
_ "github.com/lib/pq"
|
||||||
"github.com/satori/go.uuid"
|
"github.com/satori/go.uuid"
|
||||||
"golang.org/x/crypto/bcrypt"
|
|
||||||
|
"mapyweb/db"
|
||||||
|
"mapyweb/extra"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
Splash()
|
extra.Banner()
|
||||||
initDB()
|
db.StartDatabases()
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
HTTPServ()
|
HTTPServ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type authError string
|
||||||
|
|
||||||
|
const (
|
||||||
|
usernameExists authError = "username is taken"
|
||||||
|
emailExists authError = "email is taken"
|
||||||
|
rateLimited authError = "you are being ratelimited, slow down"
|
||||||
|
badEmail authError = "not a valid email address"
|
||||||
|
internalErr authError = "internal server error"
|
||||||
|
invalidRequest authError = "invalid request"
|
||||||
|
badCreds authError = "invalid credentials"
|
||||||
|
)
|
||||||
|
|
||||||
func HTTPServ() {
|
func HTTPServ() {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/", IndexShow)
|
r.HandleFunc("/", showIndex)
|
||||||
r.HandleFunc("/register", RegForm)
|
r.HandleFunc("/register", registrationForm)
|
||||||
r.HandleFunc("/login", LoginForm)
|
r.HandleFunc("/login", loginForm)
|
||||||
r.HandleFunc("/EmailTest", EmailTest)
|
r.HandleFunc("/EmailTest", EmailTest)
|
||||||
|
|
||||||
//without rate limiting
|
|
||||||
//r.HandleFunc("/login/submit", Login)
|
|
||||||
//r.HandleFunc("/register/submit", Register)
|
|
||||||
|
|
||||||
fmt.Println("Web server starting on port 42069")
|
fmt.Println("Web server starting on port 42069")
|
||||||
log.Fatal(http.ListenAndServe(":42069", csrf.Protect([]byte("7e3e2a60a55a223589f0bf218f23251619182602ae19fd829803d18645379f66"), csrf.Secure(false))(r)))
|
log.Fatal().Err(http.ListenAndServe(":42069", csrf.Protect([]byte("7e3e2a60a55a223589f0bf218f23251619182602ae19fd829803d18645379f66"), csrf.Secure(false))(r))).
|
||||||
|
Msg("http failure")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func IndexShow(w http.ResponseWriter, r *http.Request) {
|
func logAndReturnError(w http.ResponseWriter, e authError) {
|
||||||
|
log.Error().Str("error", string(e)).Msg("auth_fail")
|
||||||
|
if _, err := fmt.Fprint(w, e); err != nil {
|
||||||
|
log.Debug().Err(err).Msg("failed to write to ResponseWriter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fprinter(w http.ResponseWriter, s string, a ...interface{}) {
|
||||||
|
if _, err := fmt.Fprint(w, s, a); err != nil {
|
||||||
|
log.Debug().Err(err).Msg("failed to write to ResponseWriter")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func showIndex(w http.ResponseWriter, r *http.Request) {
|
||||||
c, err := r.Cookie("session_token")
|
c, err := r.Cookie("session_token")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if err == http.ErrNoCookie {
|
if err == http.ErrNoCookie {
|
||||||
|
@ -70,139 +97,122 @@ func IndexShow(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
http.Redirect(w, r, "/login", http.StatusSeeOther)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finally, return the welcome message to the user
|
// Finally, return the welcome message to the user
|
||||||
w.Write([]byte(fmt.Sprintf("Welcome %s!", response)))
|
fprinter(w, "Welcome %s!", response)
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoginForm(w http.ResponseWriter, r *http.Request) {
|
func loginForm(w http.ResponseWriter, r *http.Request) {
|
||||||
ip := strings.Split(r.RemoteAddr, ":")[0]
|
ip := strings.Split(r.RemoteAddr, ":")[0]
|
||||||
fmt.Println(ip)
|
fmt.Println(ip)
|
||||||
t, _ := template.ParseFiles("login.tmpl")
|
t, err := template.ParseFiles("login.tmpl")
|
||||||
t.ExecuteTemplate(w, "login.tmpl", map[string]interface{}{
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := t.ExecuteTemplate(w, "login.tmpl", map[string]interface{}{
|
||||||
csrf.TemplateTag: csrf.TemplateField(r),
|
csrf.TemplateTag: csrf.TemplateField(r),
|
||||||
})
|
}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegForm(w http.ResponseWriter, r *http.Request) {
|
func registrationForm(w http.ResponseWriter, r *http.Request) {
|
||||||
ip := strings.Split(r.RemoteAddr, ":")[0]
|
ip := strings.Split(r.RemoteAddr, ":")[0]
|
||||||
fmt.Println(ip)
|
fmt.Println(ip)
|
||||||
t, _ := template.ParseFiles("register.tmpl")
|
t, err := template.ParseFiles("register.tmpl")
|
||||||
t.ExecuteTemplate(w, "register.tmpl", map[string]interface{}{
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if err := t.ExecuteTemplate(w, "register.tmpl", map[string]interface{}{
|
||||||
csrf.TemplateTag: csrf.TemplateField(r),
|
csrf.TemplateTag: csrf.TemplateField(r),
|
||||||
})
|
}); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(w http.ResponseWriter, r *http.Request) {
|
func register(w http.ResponseWriter, r *http.Request) {
|
||||||
creds := &Credentials{}
|
var ip string
|
||||||
err := json.NewDecoder(r.Body).Decode(creds)
|
var err error
|
||||||
ip := strings.Split(r.RemoteAddr, ":")[0]
|
ip, _, err = net.SplitHostPort(r.RemoteAddr)
|
||||||
if ip == "[" {
|
if err != nil {
|
||||||
ip = "127.0.0.1"
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(ip + "/register/submit")
|
log.Debug().Str("ip", ip).Msg("register")
|
||||||
|
|
||||||
UsernameInput := r.PostFormValue("username")
|
usernameInput := r.PostFormValue("username")
|
||||||
PasswordInput := r.PostFormValue("password")
|
passwordInput := r.PostFormValue("password")
|
||||||
EmailInput := r.PostFormValue("email")
|
emailInput := r.PostFormValue("email")
|
||||||
GenderInput := r.PostFormValue("gender")
|
genderInput := r.PostFormValue("gender")
|
||||||
|
|
||||||
//debug outputs
|
// debug outputs
|
||||||
//fmt.Println(UsernameInput)
|
// fmt.Println(usernameInput)
|
||||||
//fmt.Println(PasswordInput)
|
// fmt.Println(passwordInput)
|
||||||
//fmt.Println(EmailInput)
|
// fmt.Println(emailInput)
|
||||||
//fmt.Println(GenderInput)
|
// fmt.Println(genderInput)
|
||||||
|
|
||||||
|
var gender int
|
||||||
// Verify Gender value is either 0(female) or 1(male)
|
// Verify Gender value is either 0(female) or 1(male)
|
||||||
// if not just silently send them a 400 because wtf
|
// if not just silently send them a 400 because wtf
|
||||||
if GenderInput != "0" && GenderInput != "1" {
|
if gender, err = strconv.Atoi(genderInput); err != nil || gender > 1 {
|
||||||
fmt.Println("Gender Input BAD")
|
logAndReturnError(w, invalidRequest)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Usernames must only be letters, numbers, dashes, and underscores
|
// Usernames must only be letters, numbers, dashes, and underscores
|
||||||
var rxUsername = regexp.MustCompile("([\\w\\-]+)")
|
var rxUsername = regexp.MustCompile("([\\w\\-]+)")
|
||||||
//Usernames must be under 16 characters
|
|
||||||
if len(UsernameInput) > 16 || !rxUsername.MatchString(UsernameInput) {
|
// Usernames must be under 16 characters
|
||||||
|
if len(usernameInput) > 16 || !rxUsername.MatchString(usernameInput) {
|
||||||
fmt.Println("ERROR: Username must only be alphanumeric and under 16 characters. \"-\" and \"_\" are also accepted.")
|
fmt.Println("ERROR: Username must only be alphanumeric and under 16 characters. \"-\" and \"_\" are also accepted.")
|
||||||
fmt.Println(w, "ERROR: Username must only be alphanumeric and under 16 characters. \"-\" and \"_\" are also accepted.")
|
fmt.Println(w, "ERROR: Username must only be alphanumeric and under 16 characters. \"-\" and \"_\" are also accepted.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if username is taken
|
// Check if username is taken
|
||||||
if rowExists("Select id from maplestory.accounts where username=$1", UsernameInput) {
|
if db.UserExists(usernameInput) {
|
||||||
fmt.Println("ERROR: Username exists.")
|
logAndReturnError(w, usernameExists)
|
||||||
fmt.Fprintf(w, "ERROR: Username exists.")
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Check if email is taken
|
// Check if email is taken
|
||||||
if rowExists("Select id from maplestory.accounts where email=$1", EmailInput) {
|
if db.EmailTaken(emailInput) {
|
||||||
|
logAndReturnError(w, emailExists)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
//Validates email addresses
|
// Validates email addresses
|
||||||
err = checkmail.ValidateFormat(EmailInput)
|
err = checkmail.ValidateFormat(emailInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("ERROR: that is not a valid email address!")
|
logAndReturnError(w, badEmail)
|
||||||
fmt.Fprintf(w, "ERROR: that is not a valid email address!")
|
|
||||||
//return
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("Passed checks, hashing password with bcrypt...")
|
|
||||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(PasswordInput), 16)
|
|
||||||
|
|
||||||
if _, err = db.Query("INSERT INTO maplestory.accounts (username,password,email,creation,last_login,last_ip,ban,admin,gender) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
|
||||||
UsernameInput, string(hashedPassword), EmailInput, time.Now(), time.Now(), ip, 0, 0, GenderInput); err != nil {
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
panic(err)
|
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
fmt.Println("Success!")
|
|
||||||
http.Redirect(w, r, "/?regsuccess=true", 301)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = db.RegisterNewUser(usernameInput, passwordInput, r.RemoteAddr, genderInput, false)
|
||||||
|
if err != nil {
|
||||||
|
logAndReturnError(w, internalErr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Println("Success!")
|
||||||
|
http.Redirect(w, r, "/?regsuccess=true", 301)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Login(w http.ResponseWriter, r *http.Request) {
|
func newLogin(w http.ResponseWriter, r *http.Request) {
|
||||||
UsernameInput := r.PostFormValue("username")
|
var u *db.User
|
||||||
PasswordInput := r.PostFormValue("password")
|
var err error
|
||||||
|
|
||||||
// Get the existing entry present in the database for the given username
|
usernameInput := r.PostFormValue("username")
|
||||||
result := db.QueryRow("SELECT password FROM maplestory.accounts WHERE username=$1", UsernameInput)
|
passwordInput := r.PostFormValue("password")
|
||||||
|
|
||||||
// We create another instance of `Credentials` to store the credentials we get from the database
|
if u, err = db.AttemptWebLogin(usernameInput, passwordInput, r.RemoteAddr, r.UserAgent()); err != nil {
|
||||||
storedCreds := &Credentials{}
|
logAndReturnError(w, badCreds)
|
||||||
// Store the obtained password in `storedCreds`
|
|
||||||
err := result.Scan(&storedCreds.Password)
|
|
||||||
if err != nil {
|
|
||||||
// If an entry with the username does not exist, send an "Unauthorized"(401) status
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
fmt.Println("Login failed!")
|
|
||||||
fmt.Fprintf(w, "Login failed!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// If the error is of any other type, send a 500 status
|
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare the stored hashed password, with the hashed version of the password that was received
|
|
||||||
if err = bcrypt.CompareHashAndPassword([]byte(storedCreds.Password), []byte(PasswordInput)); err != nil {
|
|
||||||
// If the two passwords don't match, return a 401 status
|
|
||||||
w.WriteHeader(http.StatusUnauthorized)
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we reach this point, that means the users password was correct, and that they are authorized
|
|
||||||
// The default 200 status is sent
|
|
||||||
|
|
||||||
fmt.Println("Authentication successful, setting session...")
|
fmt.Println("Authentication successful, setting session...")
|
||||||
|
|
||||||
//sets a 2 hour long session and cookie
|
// sets a 2 hour long session and cookie
|
||||||
sessionToken := uuid.NewV4().String()
|
sessionToken := uuid.NewV4().String()
|
||||||
_, err = cache.Do("SETEX", sessionToken, "7200", UsernameInput)
|
_, err = cache.Do("SETEX", sessionToken, "7200", usernameInput)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
fmt.Println("Session management failed!")
|
fmt.Println("Session management failed!")
|
||||||
|
@ -214,6 +224,6 @@ func Login(w http.ResponseWriter, r *http.Request) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("Login successful!")
|
fmt.Println("newLogin successful!")
|
||||||
fmt.Fprintf(w, "Login successful!")
|
fprinter(w, "newLogin successful!")
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,65 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/jmoiron/sqlx"
|
|
||||||
)
|
|
||||||
|
|
||||||
var accountsSchema = `create table accounts
|
|
||||||
(
|
|
||||||
id serial
|
|
||||||
constraint accounts_pkey
|
|
||||||
primary key,
|
|
||||||
username varchar(13) not null,
|
|
||||||
password varchar not null,
|
|
||||||
creation date not null,
|
|
||||||
last_login date not null,
|
|
||||||
last_ip varchar not null,
|
|
||||||
ban integer not null,
|
|
||||||
admin integer not null,
|
|
||||||
gender smallint default 0 not null
|
|
||||||
);`
|
|
||||||
|
|
||||||
var authlog *SecurityLog
|
|
||||||
|
|
||||||
func install(db *sqlx.DB) {
|
|
||||||
if _, err := db.Exec(accountsSchema); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
println("accounts table installed!")
|
|
||||||
}
|
|
||||||
|
|
||||||
func argParse() {
|
|
||||||
var kayos *User
|
|
||||||
var err error
|
|
||||||
for _, arg := range os.Args {
|
|
||||||
if arg == "--install" {
|
|
||||||
println("installing...")
|
|
||||||
install(db)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if arg == "--regkayos" {
|
|
||||||
println("registering kayos...")
|
|
||||||
if err := RegisterNewUser("kayos", "yeet", "127.0.0.1", 0, true); err != nil {
|
|
||||||
println("REG_TEST_FAIL: " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println("kayos registered!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if arg == "--loginkayos" {
|
|
||||||
println("logging in as kayos...")
|
|
||||||
if kayos, err = AttemptWebLogin(
|
|
||||||
"kayos",
|
|
||||||
"yeet",
|
|
||||||
"192.168.69.5",
|
|
||||||
"yeetBrowser 420"); err != nil {
|
|
||||||
println("FAIL: " + err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
println("logged in as kayos!")
|
|
||||||
println(kayos.Password)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
{
|
|
||||||
"username": "paul",
|
|
||||||
"password": "lolbad",
|
|
||||||
"email": "email@definitely.real",
|
|
||||||
"gender": 1
|
|
||||||
}
|
|
44
utils.go
44
utils.go
|
@ -1,44 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/gzip"
|
|
||||||
"encoding/base64"
|
|
||||||
"io/ioutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
const banner = "H4sIAAAAAAACA81WzYrDIBC+5xV6KXmAINhQy75ErtJbyDXs+992NVU/dWZMumxooRCcic73M2O6y/Nx/7qp1Rjz+zi6x/ny1H7t6n4hYYlxl6lW93dRrWKqz/5bBIqBGjASqzi+oQJQKUOtHbG7QRYoDk4gAaBWpXwTa4cVog5qkwQcOJa21WHJqNFnOQUhB0KiXDE4Z8H0whtOyt6XyApkWGSDOPvhN5lSVl7PVjbp0CFWIIqaTmu8QVDI9BvuHAsctxZJ2OYqyjkjB4le4komeJTfQFGwiqJCmwWTNiFLEumaKuuB9H2uDem9b6pdw6DR9yxHC4GxduTMgC17a6p7y1KbiYUVKnD0eRH1SNhVv9Sb6sUMZCnaUAPC+WX21d0yuDyspHlUbZvAoC23JRg1DOjqLEyUD94NNhMJ/QX3lV/rs7XCMQeoF2UWW75UPmRN9Q7WHJhnglZoVhFsEhMmWnk9EnNYxx5PZ9Pi4Onl15aixtzWm5Y3DQJ/PcaLrSfHctn4mYXJvUlOgVWu+GLM2jYIOKrn75T8i+HItw2hAv1BQcDkhtrbxbCRs0CW9++829MfBxoMKCsKbmx57X9Adj8mnnxLAQ4AAA=="
|
|
||||||
|
|
||||||
func qDeflate(data []byte) []byte {
|
|
||||||
var (
|
|
||||||
gz *gzip.Reader
|
|
||||||
out []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
r := bytes.NewReader(data)
|
|
||||||
if gz, err = gzip.NewReader(r); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if out, err = ioutil.ReadAll(gz); err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func b64d(data string) []byte {
|
|
||||||
var (
|
|
||||||
ret []byte
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
if ret, err = base64.StdEncoding.DecodeString(data); err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return ret
|
|
||||||
}
|
|
||||||
|
|
||||||
// Splash displays banner
|
|
||||||
func Splash() {
|
|
||||||
print(qDeflate(b64d(banner)))
|
|
||||||
println("------------- v0.2 - kayos - ra - queed squad -------------")
|
|
||||||
println("")
|
|
||||||
}
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
|
"github.com/savsgio/atreugo/v11"
|
||||||
|
|
||||||
|
config "mapyweb/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
webconf := atreugo.Config{
|
||||||
|
Addr: fmt.Sprintf("%s:%s", config.HTTPBindAddr, config.HTTPBindPort),
|
||||||
|
TLSEnable: true,
|
||||||
|
CertKey: config.SSLKey,
|
||||||
|
CertFile: config.SSLCert,
|
||||||
|
Name: "MapyWeb",
|
||||||
|
Debug: config.Debug,
|
||||||
|
Compress: true,
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
server := atreugo.New(webconf)
|
||||||
|
server.GET("/", func(ctx *atreugo.RequestCtx) error {
|
||||||
|
return ctx.TextResponse("Hello World")
|
||||||
|
})
|
||||||
|
|
||||||
|
server.GET("/echo/{path:*}", func(ctx *atreugo.RequestCtx) error {
|
||||||
|
return ctx.TextResponse("Echo message: " + ctx.UserValue("path").(string))
|
||||||
|
})
|
||||||
|
|
||||||
|
v1 := server.NewGroupPath("/v1")
|
||||||
|
v1.GET("/", func(ctx *atreugo.RequestCtx) error {
|
||||||
|
return ctx.TextResponse("Hello V1 Group")
|
||||||
|
})
|
||||||
|
|
||||||
|
log.Error().Str("caller", "http").Err(server.ListenAndServe()).Msg("failed to listen")
|
||||||
|
}
|
Loading…
Reference in New Issue