From b6a89ff06ae6393b4ea9c86e22260baba711402e Mon Sep 17 00:00:00 2001 From: Chris Sexton Date: Thu, 13 Jun 2019 10:04:06 -0400 Subject: [PATCH] web: use secret instead of human test * Applies for services that modify data * Anybody in the slack can ask for the daily secret --- bot/bot.go | 18 ++++++++++++ bot/interfaces.go | 1 + bot/mock.go | 1 + plugins/admin/admin.go | 5 ++++ plugins/cli/cli.go | 11 ++++++-- plugins/cli/index.go | 35 ++++++------------------ plugins/counter/counter.go | 13 +++++++-- plugins/counter/html.go | 56 ++++++++------------------------------ 8 files changed, 64 insertions(+), 76 deletions(-) diff --git a/bot/bot.go b/bot/bot.go index c313457..4d0c1a0 100644 --- a/bot/bot.go +++ b/bot/bot.go @@ -3,9 +3,12 @@ package bot import ( + "fmt" + "math/rand" "net/http" "reflect" "strings" + "time" "github.com/jmoiron/sqlx" "github.com/rs/zerolog/log" @@ -43,6 +46,9 @@ type bot struct { filters map[string]func(string) string callbacks CallbackMap + + password string + passwordCreated time.Time } type EndPoint struct { @@ -231,3 +237,15 @@ func (b *bot) Register(p Plugin, kind Kind, cb Callback) { func (b *bot) RegisterWeb(root, name string) { b.httpEndPoints = append(b.httpEndPoints, EndPoint{name, root}) } + +func (b *bot) GetPassword() string { + if b.passwordCreated.Before(time.Now().Add(-24 * time.Hour)) { + adjs := b.config.GetArray("bot.passwordAdjectives", []string{"very"}) + nouns := b.config.GetArray("bot.passwordNouns", []string{"noun"}) + verbs := b.config.GetArray("bot.passwordVerbs", []string{"do"}) + a, n, v := adjs[rand.Intn(len(adjs))], nouns[rand.Intn(len(nouns))], verbs[rand.Intn(len(verbs))] + b.passwordCreated = time.Now() + b.password = fmt.Sprintf("%s-%s-%s", a, n, v) + } + return b.password +} diff --git a/bot/interfaces.go b/bot/interfaces.go index d9d10d3..d9f5b62 100644 --- a/bot/interfaces.go +++ b/bot/interfaces.go @@ -67,6 +67,7 @@ type Bot interface { RegisterWeb(string, string) DefaultConnector() Connector GetWebNavigation() []EndPoint + GetPassword() string } // Connector represents a server connection to a chat service diff --git a/bot/mock.go b/bot/mock.go index 3511cf1..6d7fb70 100644 --- a/bot/mock.go +++ b/bot/mock.go @@ -32,6 +32,7 @@ func (mb *MockBot) DB() *sqlx.DB { return mb.Cfg.DB } func (mb *MockBot) Who(string) []user.User { return []user.User{} } func (mb *MockBot) WhoAmI() string { return "tester" } func (mb *MockBot) DefaultConnector() Connector { return nil } +func (mb *MockBot) GetPassword() string { return "12345" } func (mb *MockBot) Send(c Connector, kind Kind, args ...interface{}) (string, error) { switch kind { case Message: diff --git a/plugins/admin/admin.go b/plugins/admin/admin.go index b917eb2..094ec76 100644 --- a/plugins/admin/admin.go +++ b/plugins/admin/admin.go @@ -81,6 +81,11 @@ func (p *AdminPlugin) message(conn bot.Connector, k bot.Kind, message msg.Messag return true } + if strings.ToLower(body) == "password" { + p.bot.Send(conn, bot.Message, message.Channel, p.bot.GetPassword()) + return true + } + parts := strings.Split(body, " ") if parts[0] == "set" && len(parts) > 2 && forbiddenKeys[parts[1]] { p.bot.Send(conn, bot.Message, message.Channel, "You cannot access that key") diff --git a/plugins/cli/cli.go b/plugins/cli/cli.go index 13727cf..55d8875 100644 --- a/plugins/cli/cli.go +++ b/plugins/cli/cli.go @@ -42,8 +42,9 @@ func (p *CliPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) { return } info := struct { - User string `json:"user"` - Payload string `json:"payload"` + User string `json:"user"` + Payload string `json:"payload"` + Password string `json:"password"` }{} decoder := json.NewDecoder(r.Body) err := decoder.Decode(&info) @@ -55,6 +56,12 @@ func (p *CliPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) { log.Debug(). Interface("postbody", info). Msg("Got a POST") + if info.Password != p.bot.GetPassword() { + w.WriteHeader(http.StatusForbidden) + j, _ := json.Marshal(struct{ Err string }{Err: "Invalid Password"}) + w.Write(j) + return + } p.bot.Receive(p, bot.Message, msg.Message{ User: &user.User{ diff --git a/plugins/cli/index.go b/plugins/cli/index.go index bb71f50..63e9079 100644 --- a/plugins/cli/index.go +++ b/plugins/cli/index.go @@ -30,20 +30,14 @@ var indexHTML = ` + :show="err"> {{ "{{ err }}" }} - - - - - + + Password: + + { - console.log(JSON.stringify(resp.data)); const data = resp.data; this.addText(data.user, data.payload.trim()); + this.err = ''; }) .catch(err => (this.err = err)); } diff --git a/plugins/counter/counter.go b/plugins/counter/counter.go index bcb97eb..309ff47 100644 --- a/plugins/counter/counter.go +++ b/plugins/counter/counter.go @@ -566,9 +566,10 @@ func (p *CounterPlugin) handleCounter(w http.ResponseWriter, r *http.Request) { func (p *CounterPlugin) handleCounterAPI(w http.ResponseWriter, r *http.Request) { if r.Method == http.MethodPost { info := struct { - User string - Thing string - Action string + User string + Thing string + Action string + Password string }{} decoder := json.NewDecoder(r.Body) err := decoder.Decode(&info) @@ -580,6 +581,12 @@ func (p *CounterPlugin) handleCounterAPI(w http.ResponseWriter, r *http.Request) log.Debug(). Interface("postbody", info). Msg("Got a POST") + if info.Password != p.Bot.GetPassword() { + w.WriteHeader(http.StatusForbidden) + j, _ := json.Marshal(struct{ Err string }{Err: "Invalid Password"}) + w.Write(j) + return + } item, err := GetItem(p.DB, info.User, info.Thing) if err != nil { log.Error(). diff --git a/plugins/counter/html.go b/plugins/counter/html.go index 476c3c2..dd75703 100644 --- a/plugins/counter/html.go +++ b/plugins/counter/html.go @@ -27,14 +27,13 @@ var html = ` + :show="err" + variant="error"> {{ "{{ err }}" }} - Human test: What is {{ "{{ equation }}" }}? + Password: @@ -48,8 +47,8 @@ var html = ` {{ "{{ count }}" }} - - + + @@ -76,56 +75,25 @@ var html = ` nav: {{ .Nav }}, answer: '', correct: 0, - counters: { - stk5: { - beer: 12, - tea: 84, - coffee: 127 - }, - flyngpngn: { - beer: 123, - mead: 1, - tea: 130 - } - } + counters: {} }, mounted() { axios.get('/counter/api') .then(resp => (this.counters = convertData(resp.data))) .catch(err => (this.err = err)); - }, - computed: { - authenticated: function() { - if (Number(this.answer) === this.correct) - return true; - return false; - }, - equation: function() { - const x = Math.floor(Math.random() * 100); - const y = Math.floor(Math.random() * 100); - const z = Math.floor(Math.random() * 100); - const ops = ['+', '-', '*']; - const op1 = ops[Math.floor(Math.random()*3)]; - const op2 = ops[Math.floor(Math.random()*3)]; - const eq = ""+x+op1+y+op2+z; - this.correct = eval(eq); - return eq - } }, methods: { add(user, thing, count) { - this.counters[user][thing]++; axios.post('/counter/api', - {user: user, thing: thing, action: '++'}) - .then(resp => (this.counters = convertData(resp.data))) - .catch(err => (this.err = err)); + {user: user, thing: thing, action: '++', password: this.answer}) + .then(resp => {this.counters = convertData(resp.data); this.err = '';}) + .catch(err => this.err = err); }, subtract(user, thing, count) { - this.counters[user][thing]--; axios.post('/counter/api', - {user: user, thing: thing, action: '--'}) - .then(resp => (this.counters = convertData(resp.data))) - .catch(err => (this.err = err)); + {user: user, thing: thing, action: '--', password: this.answer}) + .then(resp => {this.counters = convertData(resp.data); this.err = '';}) + .catch(err => this.err = err); } } })