Merge pull request #187 from velour/password

web: use secret instead of human test
This commit is contained in:
Chris Sexton 2019-06-13 10:12:05 -04:00 committed by GitHub
commit 834c089696
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 64 additions and 76 deletions

View File

@ -3,9 +3,12 @@
package bot package bot
import ( import (
"fmt"
"math/rand"
"net/http" "net/http"
"reflect" "reflect"
"strings" "strings"
"time"
"github.com/jmoiron/sqlx" "github.com/jmoiron/sqlx"
"github.com/rs/zerolog/log" "github.com/rs/zerolog/log"
@ -43,6 +46,9 @@ type bot struct {
filters map[string]func(string) string filters map[string]func(string) string
callbacks CallbackMap callbacks CallbackMap
password string
passwordCreated time.Time
} }
type EndPoint struct { type EndPoint struct {
@ -231,3 +237,15 @@ func (b *bot) Register(p Plugin, kind Kind, cb Callback) {
func (b *bot) RegisterWeb(root, name string) { func (b *bot) RegisterWeb(root, name string) {
b.httpEndPoints = append(b.httpEndPoints, EndPoint{name, root}) 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
}

View File

@ -67,6 +67,7 @@ type Bot interface {
RegisterWeb(string, string) RegisterWeb(string, string)
DefaultConnector() Connector DefaultConnector() Connector
GetWebNavigation() []EndPoint GetWebNavigation() []EndPoint
GetPassword() string
} }
// Connector represents a server connection to a chat service // Connector represents a server connection to a chat service

View File

@ -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) Who(string) []user.User { return []user.User{} }
func (mb *MockBot) WhoAmI() string { return "tester" } func (mb *MockBot) WhoAmI() string { return "tester" }
func (mb *MockBot) DefaultConnector() Connector { return nil } 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) { func (mb *MockBot) Send(c Connector, kind Kind, args ...interface{}) (string, error) {
switch kind { switch kind {
case Message: case Message:

View File

@ -81,6 +81,11 @@ func (p *AdminPlugin) message(conn bot.Connector, k bot.Kind, message msg.Messag
return true return true
} }
if strings.ToLower(body) == "password" {
p.bot.Send(conn, bot.Message, message.Channel, p.bot.GetPassword())
return true
}
parts := strings.Split(body, " ") parts := strings.Split(body, " ")
if parts[0] == "set" && len(parts) > 2 && forbiddenKeys[parts[1]] { if parts[0] == "set" && len(parts) > 2 && forbiddenKeys[parts[1]] {
p.bot.Send(conn, bot.Message, message.Channel, "You cannot access that key") p.bot.Send(conn, bot.Message, message.Channel, "You cannot access that key")

View File

@ -42,8 +42,9 @@ func (p *CliPlugin) handleWebAPI(w http.ResponseWriter, r *http.Request) {
return return
} }
info := struct { info := struct {
User string `json:"user"` User string `json:"user"`
Payload string `json:"payload"` Payload string `json:"payload"`
Password string `json:"password"`
}{} }{}
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&info) err := decoder.Decode(&info)
@ -55,6 +56,12 @@ 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() {
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{ p.bot.Receive(p, bot.Message, msg.Message{
User: &user.User{ User: &user.User{

View File

@ -30,20 +30,14 @@ var indexHTML = `
<b-alert <b-alert
dismissable dismissable
variant="error" variant="error"
v-if="err" :show="err">
@dismissed="err = ''">
{{ "{{ err }}" }} {{ "{{ err }}" }}
</b-alert> </b-alert>
<b-container> <b-container>
<b-row> <b-row>
<b-form-group <b-col cols="5">Password:</b-col>
:label="humanTest" <b-col><b-input v-model="answer"></b-col>
label-for="input-1" </b-row>
label-cols="8"
autofocus>
<b-input v-model="answer" id="input-1" autocomplete="off"></b-input>
</b-form-group>
</b-row>
<b-row> <b-row>
<b-form-textarea <b-form-textarea
v-sticky-scroll v-sticky-scroll
@ -95,21 +89,10 @@ var indexHTML = `
}, },
computed: { computed: {
authenticated: function() { authenticated: function() {
if (Number(this.answer) === this.correct && this.user !== '') if (this.user !== '')
return true; return true;
return false; return false;
}, },
humanTest: 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 "Human test: What is " + eq + "?";
},
text: function() { text: function() {
return this.textarea.join('\n'); return this.textarea.join('\n');
} }
@ -125,18 +108,16 @@ var indexHTML = `
evt.preventDefault(); evt.preventDefault();
evt.stopPropagation() evt.stopPropagation()
if (!this.authenticated) { if (!this.authenticated) {
console.log("User is a bot.");
this.err = "User appears to be a bot.";
return; return;
} }
const payload = {user: this.user, payload: this.input}; const payload = {user: this.user, payload: this.input, password: this.answer};
this.addText(this.user, this.input); this.addText(this.user, this.input);
this.input = ""; this.input = "";
axios.post('/cli/api', payload) axios.post('/cli/api', payload)
.then(resp => { .then(resp => {
console.log(JSON.stringify(resp.data));
const data = resp.data; const data = resp.data;
this.addText(data.user, data.payload.trim()); this.addText(data.user, data.payload.trim());
this.err = '';
}) })
.catch(err => (this.err = err)); .catch(err => (this.err = err));
} }

View File

@ -566,9 +566,10 @@ func (p *CounterPlugin) handleCounter(w http.ResponseWriter, r *http.Request) {
func (p *CounterPlugin) handleCounterAPI(w http.ResponseWriter, r *http.Request) { func (p *CounterPlugin) handleCounterAPI(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost { if r.Method == http.MethodPost {
info := struct { info := struct {
User string User string
Thing string Thing string
Action string Action string
Password string
}{} }{}
decoder := json.NewDecoder(r.Body) decoder := json.NewDecoder(r.Body)
err := decoder.Decode(&info) err := decoder.Decode(&info)
@ -580,6 +581,12 @@ 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() {
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) item, err := GetItem(p.DB, info.User, info.Thing)
if err != nil { if err != nil {
log.Error(). log.Error().

View File

@ -27,14 +27,13 @@ var html = `
</b-navbar> </b-navbar>
<b-alert <b-alert
dismissable dismissable
variant="error" :show="err"
v-if="err" variant="error">
@dismissed="err = ''">
{{ "{{ err }}" }} {{ "{{ err }}" }}
</b-alert> </b-alert>
<b-container> <b-container>
<b-row> <b-row>
<b-col cols="5">Human test: What is {{ "{{ equation }}" }}?</b-col> <b-col cols="5">Password:</b-col>
<b-col><b-input v-model="answer"></b-col> <b-col><b-input v-model="answer"></b-col>
</b-row> </b-row>
<b-row v-for="(counter, user) in counters"> <b-row v-for="(counter, user) in counters">
@ -48,8 +47,8 @@ var html = `
{{ "{{ count }}" }} {{ "{{ count }}" }}
</b-col> </b-col>
<b-col cols="2"> <b-col cols="2">
<button :disabled="!authenticated" @click="subtract(user,thing,count)">-</button> <button @click="subtract(user,thing,count)">-</button>
<button :disabled="!authenticated" @click="add(user,thing,count)">+</button> <button @click="add(user,thing,count)">+</button>
</b-col> </b-col>
</b-row> </b-row>
</b-container> </b-container>
@ -76,56 +75,25 @@ var html = `
nav: {{ .Nav }}, nav: {{ .Nav }},
answer: '', answer: '',
correct: 0, correct: 0,
counters: { counters: {}
stk5: {
beer: 12,
tea: 84,
coffee: 127
},
flyngpngn: {
beer: 123,
mead: 1,
tea: 130
}
}
}, },
mounted() { mounted() {
axios.get('/counter/api') axios.get('/counter/api')
.then(resp => (this.counters = convertData(resp.data))) .then(resp => (this.counters = convertData(resp.data)))
.catch(err => (this.err = err)); .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: { methods: {
add(user, thing, count) { add(user, thing, count) {
this.counters[user][thing]++;
axios.post('/counter/api', axios.post('/counter/api',
{user: user, thing: thing, action: '++'}) {user: user, thing: thing, action: '++', password: this.answer})
.then(resp => (this.counters = convertData(resp.data))) .then(resp => {this.counters = convertData(resp.data); this.err = '';})
.catch(err => (this.err = err)); .catch(err => this.err = err);
}, },
subtract(user, thing, count) { subtract(user, thing, count) {
this.counters[user][thing]--;
axios.post('/counter/api', axios.post('/counter/api',
{user: user, thing: thing, action: '--'}) {user: user, thing: thing, action: '--', password: this.answer})
.then(resp => (this.counters = convertData(resp.data))) .then(resp => {this.counters = convertData(resp.data); this.err = '';})
.catch(err => (this.err = err)); .catch(err => this.err = err);
} }
} }
}) })