apppass: add password generation page

This commit is contained in:
Chris Sexton 2021-07-21 09:54:29 -04:00 committed by Chris Sexton
parent 64bce99455
commit 31fe84b0ba
12 changed files with 398 additions and 60 deletions

View File

@ -17,6 +17,7 @@ import (
"github.com/velour/catbase/bot/msglog" "github.com/velour/catbase/bot/msglog"
"github.com/velour/catbase/bot/user" "github.com/velour/catbase/bot/user"
"github.com/velour/catbase/config" "github.com/velour/catbase/config"
"golang.org/x/crypto/bcrypt"
) )
// bot type provides storage for bot-wide information, configs, and database connections // bot type provides storage for bot-wide information, configs, and database connections
@ -370,3 +371,23 @@ func PluginName(p Plugin) string {
t := reflect.TypeOf(p).String() t := reflect.TypeOf(p).String()
return t return t
} }
func (b *bot) CheckPassword(secret, password string) bool {
if b.password == password {
return true
}
parts := strings.SplitN(password, ":", 2)
if len(parts) == 2 {
secret = parts[0]
password = parts[1]
}
q := `select encoded_pass from apppass where secret = ?`
encodedPasswords := [][]byte{}
b.DB().Select(&encodedPasswords, q, secret)
for _, p := range encodedPasswords {
if err := bcrypt.CompareHashAndPassword(p, []byte(password)); err == nil {
return true
}
}
return false
}

View File

@ -162,6 +162,9 @@ type Bot interface {
// Check if a particular plugin is blacklisted // Check if a particular plugin is blacklisted
OnBlacklist(string, string) bool OnBlacklist(string, string) bool
// Check valid password
CheckPassword(secret, password string) bool
} }
// Connector represents a server connection to a chat service // Connector represents a server connection to a chat service

View File

@ -117,9 +117,10 @@ func NewMockBot() *MockBot {
return &b return &b
} }
func (mb *MockBot) GetPluginNames() []string { return nil } func (mb *MockBot) GetPluginNames() []string { return nil }
func (mb *MockBot) RefreshPluginBlacklist() error { return nil } func (mb *MockBot) RefreshPluginBlacklist() error { return nil }
func (mb *MockBot) RefreshPluginWhitelist() error { return nil } func (mb *MockBot) RefreshPluginWhitelist() error { return nil }
func (mb *MockBot) GetWhitelist() []string { return []string{} } func (mb *MockBot) GetWhitelist() []string { return []string{} }
func (mb *MockBot) OnBlacklist(ch, p string) bool { return false } func (mb *MockBot) OnBlacklist(ch, p string) bool { return false }
func (mb *MockBot) URLFormat(title, url string) string { return title + url } func (mb *MockBot) URLFormat(title, url string) string { return title + url }
func (mb *MockBot) CheckPassword(secret, password string) bool { return true }

View File

@ -54,7 +54,7 @@ var rootIndex = `
<script src="https://unpkg.com/vue-router"></script> <script src="https://unpkg.com/vue-router"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Factoids</title> <title>catbase</title>
</head> </head>
<body> <body>

2
go.mod
View File

@ -16,7 +16,6 @@ require (
github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect github.com/azr/backoff v0.0.0-20160115115103-53511d3c7330 // indirect
github.com/bwmarrin/discordgo v0.22.0 github.com/bwmarrin/discordgo v0.22.0
github.com/cdipaolo/goml v0.0.0-20190412180403-e1f51f713598 github.com/cdipaolo/goml v0.0.0-20190412180403-e1f51f713598
github.com/chrissexton/gofuck v1.0.0
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff
github.com/chrissexton/sentiment v0.0.0-20190927141846-d69c422ba035 github.com/chrissexton/sentiment v0.0.0-20190927141846-d69c422ba035
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect
@ -60,6 +59,7 @@ require (
github.com/ttacon/libphonenumber v1.1.0 // indirect github.com/ttacon/libphonenumber v1.1.0 // indirect
github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89 github.com/velour/chat v0.0.0-20180713122344-fd1d1606cb89
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158 github.com/velour/velour v0.0.0-20160303155839-8e090e68d158
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529
golang.org/x/exp v0.0.0-20191014171548-69215a2ee97e // indirect golang.org/x/exp v0.0.0-20191014171548-69215a2ee97e // indirect
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 // indirect golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 // indirect
gonum.org/v1/gonum v0.6.0 // indirect gonum.org/v1/gonum v0.6.0 // indirect

11
go.sum
View File

@ -1,7 +1,6 @@
code.chrissexton.org/cws/getaoc v0.0.0-20191201043947-d5417d4b618d h1:XS13tP+cMAvXYHQiYqcst64wQ854pueMRZSU4+6puU4= code.chrissexton.org/cws/getaoc v0.0.0-20191201043947-d5417d4b618d h1:XS13tP+cMAvXYHQiYqcst64wQ854pueMRZSU4+6puU4=
code.chrissexton.org/cws/getaoc v0.0.0-20191201043947-d5417d4b618d/go.mod h1:rEpfJR9MplF2TUj2Oy+u4XAaLve2kwB8I2zlzeIQxl8= code.chrissexton.org/cws/getaoc v0.0.0-20191201043947-d5417d4b618d/go.mod h1:rEpfJR9MplF2TUj2Oy+u4XAaLve2kwB8I2zlzeIQxl8=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/AlekSi/pointer v1.0.0 h1:KWCWzsvFxNLcmM5XmiqHsGTTsuwZMsLFwWF9Y+//bNE=
github.com/AlekSi/pointer v1.0.0/go.mod h1:1kjywbfcPFCmncIxtk6fIEub6LKrfMz3gc5QKVOSOA8= github.com/AlekSi/pointer v1.0.0/go.mod h1:1kjywbfcPFCmncIxtk6fIEub6LKrfMz3gc5QKVOSOA8=
github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI= github.com/AlekSi/pointer v1.1.0 h1:SSDMPcXD9jSl8FPy9cRzoRaMJtm9g9ggGTxecRUbQoI=
github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE= github.com/AlekSi/pointer v1.1.0/go.mod h1:y7BvfRI3wXPWKXEBhU71nbnIEEZX0QTSB2Bj48UJIZE=
@ -13,7 +12,6 @@ github.com/ChimeraCoder/tokenbucket v0.0.0-20131201223612-c5a927568de7/go.mod h1
github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk= github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg= github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
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/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
@ -31,8 +29,6 @@ github.com/bwmarrin/discordgo v0.22.0 h1:uBxY1HmlVCsW1IuaPjpCGT6A2DBwRn0nvOguQIx
github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M= github.com/bwmarrin/discordgo v0.22.0/go.mod h1:c1WtWUGN6nREDmzIpyTp/iD3VYt4Fpx+bVyfBG7JE+M=
github.com/cdipaolo/goml v0.0.0-20190412180403-e1f51f713598 h1:j2XRGH5Y5uWtBYXGwmrjKeM/kfu/jh7ZcnrGvyN5Ttk= github.com/cdipaolo/goml v0.0.0-20190412180403-e1f51f713598 h1:j2XRGH5Y5uWtBYXGwmrjKeM/kfu/jh7ZcnrGvyN5Ttk=
github.com/cdipaolo/goml v0.0.0-20190412180403-e1f51f713598/go.mod h1:sduMkaHcXDIWurl/Bd/z0rNEUHw5tr6LUA9IO8E9o0o= github.com/cdipaolo/goml v0.0.0-20190412180403-e1f51f713598/go.mod h1:sduMkaHcXDIWurl/Bd/z0rNEUHw5tr6LUA9IO8E9o0o=
github.com/chrissexton/gofuck v1.0.0 h1:vxg/tIfI2HunJOErSotmMqMRNfLRVO+BTjSKpFoAizA=
github.com/chrissexton/gofuck v1.0.0/go.mod h1:voOFh7xp5oNB4N516blAUT0Vh2JQq/cFX9autdChv9o=
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff h1:+TEqaP0eO1unI7XHHFeMDhsxhLDIb0x8KYuZbqbAmxA= github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff h1:+TEqaP0eO1unI7XHHFeMDhsxhLDIb0x8KYuZbqbAmxA=
github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff/go.mod h1:QCRjR0b4qiJiNjuP7RFM89bh4UExGJalcWmYeSvlnRc= github.com/chrissexton/leftpad v0.0.0-20181207133115-1e93189d2fff/go.mod h1:QCRjR0b4qiJiNjuP7RFM89bh4UExGJalcWmYeSvlnRc=
github.com/chrissexton/sentiment v0.0.0-20190927141846-d69c422ba035 h1:3+eJGFTbUgOMDCpa8PTmJABs1Z3EDHRrcz6d3oXfZm0= github.com/chrissexton/sentiment v0.0.0-20190927141846-d69c422ba035 h1:3+eJGFTbUgOMDCpa8PTmJABs1Z3EDHRrcz6d3oXfZm0=
@ -73,7 +69,6 @@ github.com/gonum/internal v0.0.0-20181124074243-f884aa714029/go.mod h1:Pu4dmpkhS
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -120,7 +115,6 @@ github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S
github.com/olebedev/when v0.0.0-20190311101825-c3b538a97254 h1:JYoQR67E1vv1WGoeW8DkdFs7vrIEe/5wP+qJItd5tUE= github.com/olebedev/when v0.0.0-20190311101825-c3b538a97254 h1:JYoQR67E1vv1WGoeW8DkdFs7vrIEe/5wP+qJItd5tUE=
github.com/olebedev/when v0.0.0-20190311101825-c3b538a97254/go.mod h1:DPucAeQGDPUzYUt+NaWw6qsF5SFapWWToxEiVDh2aV0= github.com/olebedev/when v0.0.0-20190311101825-c3b538a97254/go.mod h1:DPucAeQGDPUzYUt+NaWw6qsF5SFapWWToxEiVDh2aV0=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -137,7 +131,6 @@ github.com/slack-go/slack v0.7.2 h1:oLy2a2YqrtoHSSxbjRhrtLDGbCKcZJwgbuQ826BWxaI=
github.com/slack-go/slack v0.7.2/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM= github.com/slack-go/slack v0.7.2/go.mod h1:FGqNzJBmxIsZURAxh2a8D21AnOVvvXZvGligs4npPUM=
github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI=
github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
@ -176,11 +169,9 @@ golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCc
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a h1:oWX7TPOiFAMXLq8o0ikBYfCJVlRHBcsciT5bXOrH628=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA= golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582 h1:p9xBe/w/OzkeYVKm234g55gMdD1nSIooTir5kV11kfA=
golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191014212845-da9a3fd4c582/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@ -191,7 +182,6 @@ golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b h1:kHlr0tATeLRMEiZJu5CknOw/E8V6h69sXXQFGoPtjcc= golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b h1:kHlr0tATeLRMEiZJu5CknOw/E8V6h69sXXQFGoPtjcc=
golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210301091718-77cc2087c03b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -219,7 +209,6 @@ gopkg.in/go-playground/webhooks.v5 v5.13.0 h1:e9vtkQZK464+UdL3YjRox2yR8JSmh2094P
gopkg.in/go-playground/webhooks.v5 v5.13.0/go.mod h1:LZbya/qLVdbqDR1aKrGuWV6qbia2zCYSR5dpom2SInQ= gopkg.in/go-playground/webhooks.v5 v5.13.0/go.mod h1:LZbya/qLVdbqDR1aKrGuWV6qbia2zCYSR5dpom2SInQ=
gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI= gopkg.in/sourcemap.v1 v1.0.5 h1:inv58fC9f9J3TK2Y2R1NPntXEn3/wjWHkonhIUODNTI=
gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78= gopkg.in/sourcemap.v1 v1.0.5/go.mod h1:2RlvNNSMglmRrcvhfuzp4hQHwOtjxlbjX7UPY/GXb78=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I= gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -3,9 +3,7 @@
package admin package admin
import ( import (
"encoding/json"
"fmt" "fmt"
"net/http"
"os" "os"
"regexp" "regexp"
"strings" "strings"
@ -38,6 +36,8 @@ func New(b bot.Bot) *AdminPlugin {
cfg: b.Config(), cfg: b.Config(),
} }
p.mkDB()
b.RegisterRegex(p, bot.Message, comeBackRegex, p.comeBackCmd) b.RegisterRegex(p, bot.Message, comeBackRegex, p.comeBackCmd)
b.RegisterRegexCmd(p, bot.Message, shutupRegex, p.shutupCmd) b.RegisterRegexCmd(p, bot.Message, shutupRegex, p.shutupCmd)
b.RegisterRegexCmd(p, bot.Message, addBlacklistRegex, p.isAdmin(p.addBlacklistCmd)) b.RegisterRegexCmd(p, bot.Message, addBlacklistRegex, p.isAdmin(p.addBlacklistCmd))
@ -72,6 +72,16 @@ var forbiddenKeys = map[string]bool{
"meme.memes": true, "meme.memes": true,
} }
func (p *AdminPlugin) mkDB() {
q := `create table if not exists apppass (
id integer primary key autoincrement,
secret string not null,
encoded_pass string not null,
cost integer default 10
)`
p.db.MustExec(q)
}
var shutupRegex = regexp.MustCompile(`(?i)^shut up$`) var shutupRegex = regexp.MustCompile(`(?i)^shut up$`)
var comeBackRegex = regexp.MustCompile(`(?i)^come back$`) var comeBackRegex = regexp.MustCompile(`(?i)^come back$`)
@ -351,42 +361,6 @@ func (p *AdminPlugin) help(conn bot.Connector, kind bot.Kind, m msg.Message, arg
return true return true
} }
func (p *AdminPlugin) registerWeb() {
http.HandleFunc("/vars/api", p.handleWebAPI)
http.HandleFunc("/vars", p.handleWeb)
p.bot.RegisterWeb("/vars", "Variables")
}
func (p *AdminPlugin) handleWeb(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, varIndex)
}
func (p *AdminPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) {
var configEntries []struct {
Key string `json:"key"`
Value string `json:"value"`
}
q := `select key, value from config`
err := p.db.Select(&configEntries, q)
if err != nil {
log.Error().
Err(err).
Msg("Error getting config entries.")
w.WriteHeader(500)
fmt.Fprint(w, err)
return
}
for i, e := range configEntries {
if strings.Contains(e.Value, ";;") {
e.Value = strings.ReplaceAll(e.Value, ";;", ", ")
e.Value = fmt.Sprintf("[%s]", e.Value)
configEntries[i] = e
}
}
j, _ := json.Marshal(configEntries)
fmt.Fprintf(w, "%s", j)
}
func (p *AdminPlugin) addWhitelist(plugin string) error { func (p *AdminPlugin) addWhitelist(plugin string) error {
return p.modList(`insert or replace into pluginWhitelist values (?)`, "", plugin) return p.modList(`insert or replace into pluginWhitelist values (?)`, "", plugin)
} }

View File

@ -78,3 +78,164 @@ var varIndex = `
</body> </body>
</html> </html>
` `
var apppassIndex = `
<!DOCTYPE html>
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Load required Bootstrap and BootstrapVue CSS -->
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css"/>
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.css"/>
<!-- Load polyfills to support older browsers -->
<script src="//polyfill.io/v3/polyfill.min.js?features=es2015%2CMutationObserver"></script>
<!-- Load Vue followed by BootstrapVue -->
<script src="//unpkg.com/vue@latest/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@latest/dist/bootstrap-vue.min.js"></script>
<script src="//unpkg.com/axios/dist/axios.min.js"></script>
<meta charset="UTF-8">
<title>Vars</title>
</head>
<body>
<div id="app">
<b-navbar>
<b-navbar-brand>App Pass</b-navbar-brand>
<b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.url" :active="item.name === 'App Pass'">{{ item.name }}
</b-nav-item>
</b-navbar-nav>
</b-navbar>
<div class="alert alert-warning alert-dismissible fade show" role="alert" v-if="err != ''">
<b-button type="link" class="close" data-dismiss="alert" aria-label="Close" @click="err = ''">
<span aria-hidden="true">&times;</span>
</b-button>
{{ err }}
</div>
<b-form>
<b-container>
<b-row>
<b-col cols="5">Password:</b-col>
<b-col>
<b-input v-model="password"/>
</b-col>
</b-row>
<b-row>
<b-col cols="5">Secret:</b-col>
<b-col>
<b-input v-model="entry.secret"/>
</b-col>
</b-row>
<b-row>
<b-col>
<b-button @click="list">List</b-button>
</b-col>
<b-col>
<b-button @click="newPass">New</b-button>
</b-col>
</b-row>
</b-container>
</b-form>
<b-container v-show="showPassword" style="padding: 2em">
<b-row align-h="center">
<b-col align-self="center" cols="1">ID:</b-col>
<b-col align-self="center" cols="3">{{ entry.id }}</b-col>
</b-row>
<b-row align-h="center">
<b-col align-self="center" cols="1">Password:</b-col>
<b-col align-self="center" cols="3">{{ entry.secret }}:{{ showPassword }}</b-col>
</b-row>
<b-row align-h="center">
<b-col align-self="center" class="text-center" cols="6">Note: this password will only be displayed once. For single-field entry passwords, use the secret:password format.</b-col>
</b-row>
</b-container>
<b-container>
<b-row style="padding-top: 2em;">
<b-col>
<ul>
<li v-for="entry in entries" key="id">
<a @click="rm(entry)" href="#">X</a> {{entry.id}}</li>
</ul>
</b-col>
</b-row>
</b-container>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
err: '',
entry: {
secret: '',
},
password: '',
showPassword: '',
nav: [],
entries: [],
},
mounted() {
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
},
methods: {
rm: function (data) {
this.showPassword = '';
this.entry.id = data.id
axios.delete('/apppass/api', {
data: {
password: this.password,
passEntry: this.entry
}
})
.then(() => {
this.getData()
})
.catch(({response}) => {
console.log('error: ' + response.data.err)
this.err = response.data.err
})
},
list: function () {
this.showPassword = '';
this.getData();
},
newPass: function () {
axios.put('/apppass/api', {
password: this.password,
passEntry: this.entry
})
.then(resp => {
this.getData()
this.showPassword = resp.data.pass
this.entry.id = resp.data.id
})
.catch(({response}) => {
console.log('error: ' + response.data.err)
this.err = response.data.err
})
},
getData: function () {
axios.post('/apppass/api', {
password: this.password,
passEntry: this.entry
})
.then(resp => {
this.entries = resp.data;
})
.catch(({response}) => {
console.log('error: ' + response.data.err)
this.err = response.data.err
})
}
}
})
</script>
</body>
</html>
`

189
plugins/admin/web.go Normal file
View File

@ -0,0 +1,189 @@
package admin
import (
"crypto/md5"
"crypto/rand"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"strings"
"github.com/rs/zerolog/log"
"golang.org/x/crypto/bcrypt"
)
func (p *AdminPlugin) registerWeb() {
http.HandleFunc("/vars/api", p.handleVarsAPI)
http.HandleFunc("/vars", p.handleVars)
p.bot.RegisterWeb("/vars", "Variables")
http.HandleFunc("/apppass/verify", p.handleAppPassCheck)
http.HandleFunc("/apppass/api", p.handleAppPassAPI)
http.HandleFunc("/apppass", p.handleAppPass)
p.bot.RegisterWeb("/apppass", "App Pass")
}
func (p *AdminPlugin) handleAppPass(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, apppassIndex)
}
type PassEntry struct {
ID int64 `json:"id"`
Secret string `json:"secret"`
// Should be null unless inserting a new entry
Pass string `json:"pass"`
encodedPass []byte `json:"encodedPass"`
Cost int `json:"cost"`
}
func (p *PassEntry) EncodePass() {
encoded, err := bcrypt.GenerateFromPassword([]byte(p.Pass), p.Cost)
if err != nil {
log.Error().Err(err).Msg("could not hash password")
}
p.encodedPass = encoded
}
func (p *PassEntry) Compare(pass string) bool {
if err := bcrypt.CompareHashAndPassword(p.encodedPass, []byte(pass)); err != nil {
log.Error().Err(err).Msg("failure to match password")
return false
}
return true
}
func (p *AdminPlugin) handleAppPassCheck(w http.ResponseWriter, r *http.Request) {
req := struct {
Secret string `json:"secret"`
Password string `json:"password"`
}{}
body, _ := ioutil.ReadAll(r.Body)
_ = json.Unmarshal(body, &req)
if p.bot.CheckPassword(req.Secret, req.Password) {
w.WriteHeader(204)
} else {
w.WriteHeader(403)
}
}
func (p *AdminPlugin) handleAppPassAPI(w http.ResponseWriter, r *http.Request) {
req := struct {
Password string `json:"password"`
PassEntry PassEntry `json:"passEntry"`
}{}
body, _ := ioutil.ReadAll(r.Body)
_ = json.Unmarshal(body, &req)
if req.PassEntry.Secret == "" {
writeErr(w, fmt.Errorf("missing secret"))
return
}
if req.Password == "" || !p.bot.CheckPassword(req.PassEntry.Secret, req.Password) {
writeErr(w, fmt.Errorf("missing or incorrect password"))
return
}
switch r.Method {
case http.MethodPut:
if req.PassEntry.Secret == "" {
writeErr(w, fmt.Errorf("missing secret"))
return
}
if string(req.PassEntry.Pass) == "" {
c := 10
b := make([]byte, c)
_, err := rand.Read(b)
if err != nil {
fmt.Println("error:", err)
return
}
req.PassEntry.Pass = fmt.Sprintf("%x", md5.Sum(b))
}
q := `insert into apppass (secret, encoded_pass, cost) values (?, ?, ?)`
req.PassEntry.EncodePass()
check := bcrypt.CompareHashAndPassword(req.PassEntry.encodedPass, []byte(req.PassEntry.Pass))
log.Debug().
Str("secret", req.PassEntry.Secret).
Str("encoded", string(req.PassEntry.encodedPass)).
Str("password", string(req.PassEntry.Pass)).
Interface("check", check).
Msg("debug pass creation")
res, err := p.db.Exec(q, req.PassEntry.Secret, req.PassEntry.encodedPass, req.PassEntry.Cost)
if err != nil {
writeErr(w, err)
return
}
id, err := res.LastInsertId()
if err != nil {
writeErr(w, err)
return
}
req.PassEntry.ID = id
j, _ := json.Marshal(req.PassEntry)
fmt.Fprint(w, string(j))
return
case http.MethodDelete:
if req.PassEntry.ID <= 0 {
writeErr(w, fmt.Errorf("missing ID"))
return
}
q := `delete from apppass where id = ?`
_, err := p.db.Exec(q, req.PassEntry.ID)
if err != nil {
writeErr(w, err)
return
}
}
q := `select id,secret from apppass where secret = ?`
passEntries := []PassEntry{}
err := p.db.Select(&passEntries, q, req.PassEntry.Secret)
if err != nil {
writeErr(w, err)
return
}
j, _ := json.Marshal(passEntries)
_, _ = fmt.Fprint(w, string(j))
}
func writeErr(w http.ResponseWriter, err error) {
log.Error().Err(err).Msg("apppass error")
j, _ := json.Marshal(struct {
Err string `json:"err"`
}{
err.Error(),
})
w.WriteHeader(400)
fmt.Fprint(w, string(j))
}
func (p *AdminPlugin) handleVars(w http.ResponseWriter, r *http.Request) {
fmt.Fprint(w, varIndex)
}
func (p *AdminPlugin) handleVarsAPI(w http.ResponseWriter, r *http.Request) {
var configEntries []struct {
Key string `json:"key"`
Value string `json:"value"`
}
q := `select key, value from config`
err := p.db.Select(&configEntries, q)
if err != nil {
log.Error().
Err(err).
Msg("Error getting config entries.")
w.WriteHeader(500)
fmt.Fprint(w, err)
return
}
for i, e := range configEntries {
if strings.Contains(e.Value, ";;") {
e.Value = strings.ReplaceAll(e.Value, ";;", ", ")
e.Value = fmt.Sprintf("[%s]", e.Value)
configEntries[i] = e
}
}
j, _ := json.Marshal(configEntries)
fmt.Fprintf(w, "%s", j)
}

View File

@ -57,7 +57,7 @@ func (p *CliPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) {
log.Debug(). log.Debug().
Interface("postbody", info). Interface("postbody", info).
Msg("Got a POST") Msg("Got a POST")
if info.Password != p.bot.GetPassword() { if !p.bot.CheckPassword("", info.Password) {
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
j, _ := json.Marshal(struct{ Err string }{Err: "Invalid Password"}) j, _ := json.Marshal(struct{ Err string }{Err: "Invalid Password"})
w.Write(j) w.Write(j)

View File

@ -745,7 +745,7 @@ func (p *CounterPlugin) handleCounterAPI(w http.ResponseWriter, r *http.Request)
log.Debug(). log.Debug().
Interface("postbody", info). Interface("postbody", info).
Msg("Got a POST") Msg("Got a POST")
if info.Password != p.Bot.GetPassword() { if p.Bot.CheckPassword("", info.Password) {
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusForbidden)
j, _ := json.Marshal(struct{ Err string }{Err: "Invalid Password"}) j, _ := json.Marshal(struct{ Err string }{Err: "Invalid Password"})
w.Write(j) w.Write(j)

View File

@ -150,7 +150,7 @@ func (p *FirstPlugin) isNotToday(f *FirstEntry) bool {
t := f.time t := f.time
t0 := Midnight(t) t0 := Midnight(t)
jitter := time.Duration(p.config.GetInt("first.jitter", 0)) jitter := time.Duration(p.config.GetInt("first.jitter", 0))
t0 = t0.Add(jitter * time.Second) t0 = t0.Add(jitter * time.Millisecond)
return t0.Before(Midnight(time.Now())) return t0.Before(Midnight(time.Now()))
} }