Compare commits

..

7 Commits

Author SHA1 Message Date
Chris Sexton def86a3c7e list: implement last as a reply to the last message 2024-03-19 11:29:36 -04:00
Chris Sexton 35499ee213 meme: use httpin 2024-03-19 11:29:36 -04:00
Chris Sexton 674e30125b fact: use httpin 2024-03-19 11:29:36 -04:00
Chris Sexton 28e9fc2480 secrets: use httpin 2024-03-19 11:29:36 -04:00
Chris Sexton b73e64ad72 admin: apppass uses httpin 2024-03-19 11:29:36 -04:00
Chris Sexton a6d224c87b emojy: handle with httpin 2024-03-19 11:29:36 -04:00
Chris Sexton 81fb3dd068 counter: try out httpin 2024-03-19 11:29:36 -04:00
17 changed files with 296 additions and 348 deletions

View File

@ -63,6 +63,12 @@ type File struct {
mime *mimetype.MIME
}
type MessageReference struct {
MessageID string `json:"message_id"`
ChannelID string `json:"channel_id,omitempty"`
GuildID string `json:"guild_id,omitempty"`
}
func (f File) Mime() *mimetype.MIME {
if f.mime == nil {
f.mime = mimetype.Detect(f.Data)

View File

@ -11,6 +11,8 @@ import (
"net/http"
"strings"
"time"
httpin_integration "github.com/ggicci/httpin/integration"
)
type Web struct {
@ -77,6 +79,8 @@ func (ws *Web) setupHTTP() {
ws.router.Use(middleware.Recoverer)
ws.router.Use(middleware.StripSlashes)
httpin_integration.UseGochiURLParam("path", chi.URLParam)
ws.router.HandleFunc("/", ws.serveRoot)
ws.router.HandleFunc("/nav", ws.serveNav)
ws.router.HandleFunc("/navHTML", ws.serveNavHTML)

View File

@ -116,6 +116,7 @@ func (d *Discord) sendMessage(channel, message string, meMessage bool, args ...a
embeds := []*discordgo.MessageEmbed{}
files := []*discordgo.File{}
var ref *discordgo.MessageReference
for _, arg := range args {
switch a := arg.(type) {
@ -141,6 +142,12 @@ func (d *Discord) sendMessage(channel, message string, meMessage bool, args ...a
ContentType: a.ContentType(),
Reader: bytes.NewBuffer(a.Data),
})
case bot.MessageReference:
ref = &discordgo.MessageReference{
MessageID: a.MessageID,
ChannelID: a.ChannelID,
GuildID: a.GuildID,
}
}
}
@ -148,6 +155,7 @@ func (d *Discord) sendMessage(channel, message string, meMessage bool, args ...a
Content: message,
Embeds: embeds,
Files: files,
Reference: ref,
}
log.Debug().

6
go.mod
View File

@ -17,7 +17,8 @@ require (
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90
github.com/forPelevin/gomoji v1.1.6
github.com/gabriel-vasile/mimetype v1.4.1
github.com/go-chi/chi/v5 v5.0.7
github.com/ggicci/httpin v0.16.0
github.com/go-chi/chi/v5 v5.0.11
github.com/go-chi/httprate v0.7.0
github.com/gocolly/colly v1.2.0
github.com/google/uuid v1.3.0
@ -32,7 +33,7 @@ require (
github.com/olebedev/when v0.0.0-20190311101825-c3b538a97254
github.com/rs/zerolog v1.28.0
github.com/slack-go/slack v0.11.3
github.com/stretchr/testify v1.8.2
github.com/stretchr/testify v1.8.4
github.com/trubitsyn/go-zero-width v1.0.1
github.com/velour/velour v0.0.0-20160303155839-8e090e68d158
golang.org/x/crypto v0.14.0
@ -57,6 +58,7 @@ require (
github.com/dustin/go-jsonpointer v0.0.0-20160814072949-ba0abeacc3dc // indirect
github.com/dustin/gojson v0.0.0-20160307161227-2e71ec9dd5ad // indirect
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 // indirect
github.com/ggicci/owl v0.7.0 // indirect
github.com/go-stack/stack v1.8.0 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect

14
go.sum
View File

@ -120,9 +120,13 @@ github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkF
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17 h1:GOfMz6cRgTJ9jWV0qAezv642OhPnKEG7gtUjJSdStHE=
github.com/garyburd/go-oauth v0.0.0-20180319155456-bca2e7f09a17/go.mod h1:HfkOCN6fkKKaPSAeNq/er3xObxTW4VLeY6UUK895gLQ=
github.com/ggicci/httpin v0.16.0 h1:ZR6RXH1xNWg39xqM33V7iz7PP/GuR7vc3aHa2g5mWo4=
github.com/ggicci/httpin v0.16.0/go.mod h1:whE/5nx1jCp//UQ6rgNpq2WNxOr9FV0OpxMnQQC0Xvs=
github.com/ggicci/owl v0.7.0 h1:+AMlCR0AY7j72q7hjtN4pm8VJiikwpROtMgvPnXtuik=
github.com/ggicci/owl v0.7.0/go.mod h1:TRPWshRwYej6uES//YW5aNgLB370URwyta1Ytfs7KXs=
github.com/go-chi/chi v1.5.4 h1:QHdzF2szwjqVV4wmByUnTcsbIg7UGaQ0tPF2t5GcAIs=
github.com/go-chi/chi/v5 v5.0.7 h1:rDTPXLDHGATaeHvVlLcR4Qe0zftYethFucbjVQ1PxU8=
github.com/go-chi/chi/v5 v5.0.7/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/httprate v0.7.0 h1:8W0dF7Xa2Duz2p8ncGaehIphrxQGNlOtoGY0+NRRfjQ=
github.com/go-chi/httprate v0.7.0/go.mod h1:6GOYBSwnpra4CQfAKXu8sQZg+nZ0M1g9QnyFvxrAB8A=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
@ -215,6 +219,7 @@ 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.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -252,6 +257,7 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes=
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
github.com/kennygrant/sanitize v1.2.4 h1:gN25/otpP5vAsO2djbMhF/LQX6R7+O1TB4yv8NzpJ3o=
github.com/kennygrant/sanitize v1.2.4/go.mod h1:LGsjYYtgxbetdg5owWB2mpgUL6e2nfw2eObZ0u0qvak=
github.com/kevinburke/go-types v0.0.0-20200309064045-f2d4aea18a7a h1:Z7+SSApKiwPjNic+NF9+j7h657Uyvdp/jA3iTKhpj4E=
@ -372,8 +378,8 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/temoto/robotstxt v1.1.1 h1:Gh8RCs8ouX3hRSxxK7B1mO5RFByQ4CmJZDwgom++JaA=
github.com/temoto/robotstxt v1.1.1/go.mod h1:+1AmkuG3IYkh1kv0d2qEB9Le88ehNO0zwOr3ujewlOo=
github.com/trubitsyn/go-zero-width v1.0.1 h1:AAZhtyGXW79T5BouAF0R9FtDhGcp7IGbLZo2Id3N+m8=

View File

@ -24,17 +24,17 @@ templ (a *AdminPlugin) page() {
<button hx-put="/apppass/api" hx-target="#data" class="submit success button">New</button>
</div>
</div>
</form>
<div class="grid-x">
<div class="cell" id="data"></div>
</div>
</form>
</div>
}
templ (a *AdminPlugin) showPassword(entry PassEntry) {
<div><span>ID</span><span>{ fmt.Sprintf("%d", entry.ID) }</span></div>
<div><span>Password</span><span>{ entry.Secret }:{ entry.Pass }</span></div>
<div><span style="margin-right: 2em">ID</span><span>{ fmt.Sprintf(" %d", entry.ID) }</span></div>
<div><span style="margin-right: 2em">Password</span><span> { entry.Secret }:{ entry.Pass }</span></div>
}
templ (a *AdminPlugin) entries(items []PassEntry) {
@ -51,7 +51,6 @@ templ (a *AdminPlugin) entries(items []PassEntry) {
hx-delete="/apppass/api"
hx-confirm={ fmt.Sprintf("Are you sure you want to delete %d?", entry.ID) }
hx-target="#data"
hx-include="this,[name='password'],[name='secret']"
name="id" value={ fmt.Sprintf("%d", entry.ID) }>X</button>
{ fmt.Sprintf("%d", entry.ID) }
</li>

View File

@ -25,7 +25,7 @@ func (a *AdminPlugin) page() templ.Component {
templ_7745c5c3_Var1 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"grid-container\"><form><div class=\"grid-x grid-margin-x align-bottom\"><h2>App Pass</h2></div><div class=\"grid-x grid-margin-x align-bottom\"><div class=\"cell auto\"><label for=\"password\">Password: <input type=\"text\" name=\"password\"></label></div><div class=\"cell auto\"><label for=\"secret\">Secret: <input type=\"text\" name=\"secret\"></label></div><div class=\"cell auto\"><button hx-post=\"/apppass/api\" hx-target=\"#data\" class=\"button\">List</button> <button hx-put=\"/apppass/api\" hx-target=\"#data\" class=\"submit success button\">New</button></div></div></form><div class=\"grid-x\"><div class=\"cell\" id=\"data\"></div></div></div>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div class=\"grid-container\"><form><div class=\"grid-x grid-margin-x align-bottom\"><h2>App Pass</h2></div><div class=\"grid-x grid-margin-x align-bottom\"><div class=\"cell auto\"><label for=\"password\">Password: <input type=\"text\" name=\"password\"></label></div><div class=\"cell auto\"><label for=\"secret\">Secret: <input type=\"text\" name=\"secret\"></label></div><div class=\"cell auto\"><button hx-post=\"/apppass/api\" hx-target=\"#data\" class=\"button\">List</button> <button hx-put=\"/apppass/api\" hx-target=\"#data\" class=\"submit success button\">New</button></div></div><div class=\"grid-x\"><div class=\"cell\" id=\"data\"></div></div></form></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -49,27 +49,27 @@ func (a *AdminPlugin) showPassword(entry PassEntry) templ.Component {
templ_7745c5c3_Var2 = templ.NopComponent
}
ctx = templ.ClearChildren(ctx)
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div><span>ID</span><span>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div><span style=\"margin-right: 2em\">ID</span><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var3 string
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf(" %d", entry.ID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 35, Col: 59}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 35, Col: 86}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div><div><span>Password</span><span>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div><div><span style=\"margin-right: 2em\">Password</span><span>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var4 string
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Secret)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 36, Col: 50}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 36, Col: 77}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
if templ_7745c5c3_Err != nil {
@ -82,7 +82,7 @@ func (a *AdminPlugin) showPassword(entry PassEntry) templ.Component {
var templ_7745c5c3_Var5 string
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(entry.Pass)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 36, Col: 65}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 36, Col: 92}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
if templ_7745c5c3_Err != nil {
@ -135,7 +135,7 @@ func (a *AdminPlugin) entries(items []PassEntry) templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-target=\"#data\" hx-include=\"this,[name=&#39;password&#39;],[name=&#39;secret&#39;]\" name=\"id\" value=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-target=\"#data\" name=\"id\" value=\"")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
@ -150,7 +150,7 @@ func (a *AdminPlugin) entries(items []PassEntry) templ.Component {
var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d", entry.ID))
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 55, Col: 57}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 54, Col: 57}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil {
@ -192,7 +192,7 @@ func renderError(err error) templ.Component {
var templ_7745c5c3_Var9 string
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(err.Error())
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 63, Col: 22}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 62, Col: 22}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
if templ_7745c5c3_Err != nil {
@ -234,7 +234,7 @@ func vars(items []configEntry) templ.Component {
var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(item.Key)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 79, Col: 38}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 78, Col: 38}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil {
@ -247,7 +247,7 @@ func vars(items []configEntry) templ.Component {
var templ_7745c5c3_Var12 string
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(item.Value)
if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 79, Col: 61}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 78, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {

View File

@ -4,13 +4,12 @@ import (
"context"
"crypto/md5"
"crypto/rand"
"encoding/json"
"fmt"
"github.com/ggicci/httpin"
"github.com/go-chi/chi/v5"
"github.com/rs/zerolog/log"
"golang.org/x/crypto/bcrypt"
"io"
"io/ioutil"
"net/http"
"net/url"
"strconv"
@ -21,8 +20,15 @@ func (p *AdminPlugin) registerWeb() {
r.HandleFunc("/", p.handleVars)
p.bot.GetWeb().RegisterWebName(r, "/vars", "Variables")
r = chi.NewRouter()
r.HandleFunc("/verify", p.handleAppPassCheck)
r.HandleFunc("/api", p.handleAppPassAPI)
r.With(httpin.NewInput(AppPassCheckReq{})).
HandleFunc("/verify", p.handleAppPassCheck)
//r.HandleFunc("/api", p.handleAppPassAPI)
r.With(httpin.NewInput(AppPassAPIReq{})).
Put("/api", p.handleAppPassAPIPut)
r.With(httpin.NewInput(AppPassAPIReq{})).
Delete("/api", p.handleAppPassAPIDelete)
r.With(httpin.NewInput(AppPassAPIReq{})).
Post("/api", p.handleAppPassAPIPost)
r.HandleFunc("/", p.handleAppPass)
p.bot.GetWeb().RegisterWebName(r, "/apppass", "App Pass")
}
@ -32,8 +38,8 @@ func (p *AdminPlugin) handleAppPass(w http.ResponseWriter, r *http.Request) {
}
type PassEntry struct {
ID int64 `json:"id"`
Secret string `json:"secret"`
ID int64 `json:"id" in:"form=id;query=password"`
Secret string `json:"secret" in:"form=secret;query=password"`
// Should be null unless inserting a new entry
Pass string `json:"pass"`
@ -57,57 +63,55 @@ func (p *PassEntry) Compare(pass string) bool {
return true
}
func (p *AdminPlugin) handleAppPassCheck(w http.ResponseWriter, r *http.Request) {
req := struct {
type AppPassCheckReq 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) {
}
func (p *AdminPlugin) handleAppPassCheck(w http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*AppPassCheckReq)
if p.bot.CheckPassword(input.Secret, input.Password) {
w.WriteHeader(204)
} else {
w.WriteHeader(403)
}
}
func (p *AdminPlugin) handleAppPassAPI(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
type AppPassAPIReq struct {
Password string `in:"form=password;query=password"`
PassEntry PassEntry
}
func (p *AdminPlugin) checkAPIInput(w http.ResponseWriter, r *http.Request) *AppPassAPIReq {
input := r.Context().Value(httpin.Input).(*AppPassAPIReq)
if input.Password == "" && input.PassEntry.Secret == "" {
b, _ := io.ReadAll(r.Body)
query, _ := url.ParseQuery(string(b))
secret := r.FormValue("secret")
password := r.FormValue("password")
id, _ := strconv.ParseInt(r.FormValue("id"), 10, 64)
if !r.Form.Has("secret") && query.Has("secret") {
secret = query.Get("secret")
input.Password = query.Get("password")
input.PassEntry.ID, _ = strconv.ParseInt(query.Get("id"), 10, 64)
input.PassEntry.Secret = query.Get("secret")
}
if !r.Form.Has("password") && query.Has("password") {
password = query.Get("password")
}
if !r.Form.Has("id") && query.Has("id") {
id, _ = strconv.ParseInt(query.Get("id"), 10, 64)
}
req := struct {
Password string `json:"password"`
PassEntry PassEntry `json:"passEntry"`
}{
password,
PassEntry{
ID: id,
Secret: secret,
},
}
if req.PassEntry.Secret == "" {
log.Printf("checkAPIInput: %#v", input)
if input.PassEntry.Secret == "" {
writeErr(r.Context(), w, fmt.Errorf("missing secret"))
return
return nil
}
if req.Password == "" || !p.bot.CheckPassword(req.PassEntry.Secret, req.Password) {
if input.Password == "" || !p.bot.CheckPassword(input.PassEntry.Secret, input.Password) {
writeErr(r.Context(), w, fmt.Errorf("missing or incorrect password"))
return nil
}
return input
}
func (p *AdminPlugin) handleAppPassAPIPut(w http.ResponseWriter, r *http.Request) {
input := p.checkAPIInput(w, r)
if input == nil {
return
}
switch r.Method {
case http.MethodPut:
if string(req.PassEntry.Pass) == "" {
if string(input.PassEntry.Pass) == "" {
c := 10
b := make([]byte, c)
_, err := rand.Read(b)
@ -115,21 +119,21 @@ func (p *AdminPlugin) handleAppPassAPI(w http.ResponseWriter, r *http.Request) {
fmt.Println("error:", err)
return
}
req.PassEntry.Pass = fmt.Sprintf("%x", md5.Sum(b))
input.PassEntry.Pass = fmt.Sprintf("%x", md5.Sum(b))
}
q := `insert into apppass (secret, encoded_pass, cost) values (?, ?, ?)`
req.PassEntry.EncodePass()
input.PassEntry.EncodePass()
check := bcrypt.CompareHashAndPassword(req.PassEntry.encodedPass, []byte(req.PassEntry.Pass))
check := bcrypt.CompareHashAndPassword(input.PassEntry.encodedPass, []byte(input.PassEntry.Pass))
log.Debug().
Str("secret", req.PassEntry.Secret).
Str("encoded", string(req.PassEntry.encodedPass)).
Str("password", string(req.PassEntry.Pass)).
Str("secret", input.PassEntry.Secret).
Str("encoded", string(input.PassEntry.encodedPass)).
Str("password", string(input.PassEntry.Pass)).
Interface("check", check).
Msg("debug pass creation")
res, err := p.db.Exec(q, req.PassEntry.Secret, req.PassEntry.encodedPass, req.PassEntry.Cost)
res, err := p.db.Exec(q, input.PassEntry.Secret, input.PassEntry.encodedPass, input.PassEntry.Cost)
if err != nil {
writeErr(r.Context(), w, err)
return
@ -139,25 +143,37 @@ func (p *AdminPlugin) handleAppPassAPI(w http.ResponseWriter, r *http.Request) {
writeErr(r.Context(), w, err)
return
}
req.PassEntry.ID = id
p.showPassword(req.PassEntry).Render(r.Context(), w)
return
case http.MethodDelete:
input.PassEntry.ID = id
p.showPassword(input.PassEntry).Render(r.Context(), w)
}
if req.PassEntry.ID <= 0 {
func (p *AdminPlugin) handleAppPassAPIDelete(w http.ResponseWriter, r *http.Request) {
input := p.checkAPIInput(w, r)
if input == nil {
return
}
if input.PassEntry.ID <= 0 {
writeErr(r.Context(), w, fmt.Errorf("missing ID"))
return
}
q := `delete from apppass where id = ?`
_, err := p.db.Exec(q, req.PassEntry.ID)
_, err := p.db.Exec(q, input.PassEntry.ID)
if err != nil {
writeErr(r.Context(), w, err)
return
}
p.handleAppPassAPIPost(w, r)
}
func (p *AdminPlugin) handleAppPassAPIPost(w http.ResponseWriter, r *http.Request) {
input := p.checkAPIInput(w, r)
if input == nil {
return
}
q := `select id,secret from apppass where secret = ?`
passEntries := []PassEntry{}
err := p.db.Select(&passEntries, q, req.PassEntry.Secret)
err := p.db.Select(&passEntries, q, input.PassEntry.Secret)
if err != nil {
writeErr(r.Context(), w, err)
return

View File

@ -3,10 +3,8 @@ package counter
import (
"encoding/json"
"fmt"
"io"
"github.com/ggicci/httpin"
"net/http"
"net/url"
"strconv"
"time"
"github.com/go-chi/chi/v5"
@ -23,34 +21,48 @@ func (p *CounterPlugin) registerWeb() {
dur := time.Duration(seconds) * time.Second
subrouter := chi.NewRouter()
subrouter.Use(httprate.LimitByIP(requests, dur))
subrouter.HandleFunc("/api/users/{user}/items/{item}/increment/{delta}", p.mkIncrementByNAPI(1))
subrouter.HandleFunc("/api/users/{user}/items/{item}/decrement/{delta}", p.mkIncrementByNAPI(-1))
subrouter.HandleFunc("/api/users/{user}/items/{item}/increment", p.mkIncrementByNAPI(1))
subrouter.HandleFunc("/api/users/{user}/items/{item}/decrement", p.mkIncrementByNAPI(-1))
subrouter.With(httpin.NewInput(CounterChangeReq{})).
HandleFunc("/api/users/{user}/items/{item}/increment/{delta}", p.mkIncrementByNAPI(1))
subrouter.With(httpin.NewInput(CounterChangeReq{})).
HandleFunc("/api/users/{user}/items/{item}/decrement/{delta}", p.mkIncrementByNAPI(-1))
subrouter.With(httpin.NewInput(CounterChangeReq{})).
HandleFunc("/api/users/{user}/items/{item}/increment", p.mkIncrementByNAPI(1))
subrouter.With(httpin.NewInput(CounterChangeReq{})).
HandleFunc("/api/users/{user}/items/{item}/decrement", p.mkIncrementByNAPI(-1))
r.Mount("/", subrouter)
r.HandleFunc("/users/{user}/items/{item}/increment", p.incHandler(1))
r.HandleFunc("/users/{user}/items/{item}/decrement", p.incHandler(-1))
r.With(httpin.NewInput(CounterChangeReq{})).
HandleFunc("/users/{user}/items/{item}/increment", p.incHandler(1))
r.With(httpin.NewInput(CounterChangeReq{})).
HandleFunc("/users/{user}/items/{item}/decrement", p.incHandler(-1))
r.HandleFunc("/", p.handleCounter)
p.b.GetWeb().RegisterWebName(r, "/counter", "Counter")
}
type CounterChangeReq struct {
UserName string `in:"path=user"`
Item string `in:"path=item"`
Password string `in:"form=password"`
Delta int `in:"path=delta"`
Body struct {
Message string `json:"message"`
} `in:"body=json"`
}
func (p *CounterPlugin) incHandler(delta int) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
userName, _ := url.QueryUnescape(chi.URLParam(r, "user"))
itemName, _ := url.QueryUnescape(chi.URLParam(r, "item"))
pass := r.FormValue("password")
if !p.b.CheckPassword("", pass) {
input := r.Context().Value(httpin.Input).(*CounterChangeReq)
if !p.b.CheckPassword("", input.Password) {
w.WriteHeader(401)
fmt.Fprintf(w, "error")
return
}
item, err := p.delta(userName, itemName, "", delta)
item, err := p.delta(input.UserName, input.Item, "", delta)
if err != nil {
w.WriteHeader(500)
fmt.Fprintf(w, "error")
return
}
p.renderItem(userName, item).Render(r.Context(), w)
p.renderItem(input.UserName, item).Render(r.Context(), w)
}
}
@ -103,13 +115,11 @@ func (p *CounterPlugin) delta(userName, itemName, personalMessage string, delta
func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
userName, _ := url.QueryUnescape(chi.URLParam(r, "user"))
itemName, _ := url.QueryUnescape(chi.URLParam(r, "item"))
delta, err := strconv.Atoi(chi.URLParam(r, "delta"))
if err != nil || delta == 0 {
delta = direction
input := r.Context().Value(httpin.Input).(*CounterChangeReq)
if input.Delta == 0 {
input.Delta = direction
} else {
delta = delta * direction
input.Delta = input.Delta * direction
}
secret, pass, ok := r.BasicAuth()
@ -127,15 +137,12 @@ func (p *CounterPlugin) mkIncrementByNAPI(direction int) func(w http.ResponseWri
return
}
body, _ := io.ReadAll(r.Body)
postData := map[string]string{}
err = json.Unmarshal(body, &postData)
personalMsg := ""
if inputMsg, ok := postData["message"]; ok {
personalMsg = fmt.Sprintf("\nMessage: %s", inputMsg)
if input.Body.Message != "" {
personalMsg = fmt.Sprintf("\nMessage: %s", input.Body.Message)
}
if _, err := p.delta(userName, itemName, personalMsg, delta*direction); err != nil {
if _, err := p.delta(input.UserName, input.Item, personalMsg, input.Delta*direction); err != nil {
log.Error().Err(err).Msg("error finding item")
w.WriteHeader(400)
j, _ := json.Marshal(struct {

View File

@ -1,104 +0,0 @@
<html>
<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@^2/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@^2/dist/vue.min.js"></script>
<script src="//unpkg.com/bootstrap-vue@^2/dist/bootstrap-vue.min.js"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<title>Counters</title>
</head>
<body>
<div id="app">
<b-navbar>
<b-navbar-brand>Counters</b-navbar-brand>
<b-navbar-nav>
<b-nav-item v-for="item in nav" :href="item.url" :active="item.name === 'Counter'">{{ item.name }}</b-nav-item>
</b-navbar-nav>
</b-navbar>
<b-alert
dismissable
:show="err"
variant="error">
{{ err }}
</b-alert>
<b-container>
<b-row>
<b-col cols="5">Password:</b-col>
<b-col><b-input v-model="answer"></b-col>
</b-row>
<b-row v-for="(counter, user) in counters">
{{ user }}:
<b-container>
<b-row v-for="(count, thing) in counter">
<b-col offset="1">
{{ thing }}:
</b-col>
<b-col>
{{ count }}
</b-col>
<b-col cols="2">
<button @click="subtract(user,thing,count)">-</button>
<button @click="add(user,thing,count)">+</button>
</b-col>
</b-row>
</b-container>
</b-row>
</b-container>
</div>
<script>
function convertData(data) {
var newData = {};
for (let i = 0; i < data.length; i++) {
let entry = data[i]
if (newData[entry.Nick] === undefined) {
newData[entry.Nick] = {}
}
newData[entry.Nick][entry.Item] = entry.Count;
}
return newData;
}
var app = new Vue({
el: '#app',
data: {
err: '',
nav: [],
answer: '',
correct: 0,
counters: {}
},
mounted() {
axios.get('/nav')
.then(resp => {
this.nav = resp.data;
})
.catch(err => console.log(err))
axios.get('/counter/api')
.then(resp => (this.counters = convertData(resp.data)))
.catch(err => (this.err = err));
},
methods: {
add(user, thing, count) {
axios.post('/counter/api',
{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) {
axios.post('/counter/api',
{user: user, thing: thing, action: '--', password: this.answer})
.then(resp => {this.counters = convertData(resp.data); this.err = '';})
.catch(err => this.err = err);
}
}
})
</script>
</body>
</html>

View File

@ -12,6 +12,7 @@ templ (p *EmojyPlugin) uploadIndex() {
@p.emojyNav()
</div>
</div>
<form hx-post="/emojy/upload" enctype="multipart/form-data">
<div class="grid-x">
<div class="cell">
<label>Passphrase</label>
@ -19,12 +20,13 @@ templ (p *EmojyPlugin) uploadIndex() {
</div>
<div class="cell">
<label>File
<input type="file" />
<input type="file" name="attachment" />
</label>
</div>
<div class="cell">
<button class="button" hx-post="/emojy/upload">Submit</button>
<button class="button" type="submit">Submit</button>
</div>
</div>
</form>
</div>
}

View File

@ -31,7 +31,7 @@ func (p *EmojyPlugin) uploadIndex() templ.Component {
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><div class=\"grid-x\"><div class=\"cell\"><label>Passphrase</label> <input type=\"text\" name=\"password\" placeholder=\"Password...\"></div><div class=\"cell\"><label>File <input type=\"file\"></label></div><div class=\"cell\"><button class=\"button\" hx-post=\"/emojy/upload\">Submit</button></div></div></div>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</div></div><form hx-post=\"/emojy/upload\" enctype=\"multipart/form-data\"><div class=\"grid-x\"><div class=\"cell\"><label>Passphrase</label> <input type=\"text\" name=\"password\" placeholder=\"Password...\"></div><div class=\"cell\"><label>File <input type=\"file\" name=\"attachment\"></label></div><div class=\"cell\"><button class=\"button\" type=\"submit\">Submit</button></div></div></form></div>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -4,6 +4,7 @@ import (
"embed"
"encoding/json"
"fmt"
"github.com/ggicci/httpin"
"io"
"io/ioutil"
"net/http"
@ -23,8 +24,10 @@ func (p *EmojyPlugin) registerWeb() {
r := chi.NewRouter()
r.HandleFunc("/all", p.handleAll)
r.HandleFunc("/allFiles", p.handleAllFiles)
r.HandleFunc("/upload", p.handleUpload)
r.HandleFunc("/file/{name}", p.handleEmojy)
r.With(httpin.NewInput(UploadReq{})).
Post("/upload", p.handleUpload)
r.With(httpin.NewInput(EmojyReq{})).
HandleFunc("/file/{name}", p.handleEmojy)
r.HandleFunc("/stats", p.handleStats)
r.HandleFunc("/list", p.handleList)
r.HandleFunc("/new", p.handleUploadForm)
@ -98,8 +101,15 @@ func (p *EmojyPlugin) handleAllFiles(w http.ResponseWriter, r *http.Request) {
}
}
type UploadReq struct {
Password string `in:"form=password"`
Attachment *httpin.File `in:"form=attachment"`
}
func (p *EmojyPlugin) handleUpload(w http.ResponseWriter, r *http.Request) {
newFilePath, err := p.FileSave(r)
input := r.Context().Value(httpin.Input).(*UploadReq)
log.Printf("handleUpload: %#v", input)
newFilePath, err := p.FileSave(input)
if err != nil {
log.Error().Err(err).Msgf("could not upload file")
w.WriteHeader(500)
@ -111,60 +121,46 @@ func (p *EmojyPlugin) handleUpload(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "success")
}
func (p *EmojyPlugin) FileSave(r *http.Request) (string, error) {
if err := r.ParseMultipartForm(32 << 20); err != nil {
if err != http.ErrNotMultipart {
return "", err
}
if err := r.ParseForm(); err != nil {
return "", err
}
}
if r.MultipartForm == nil || len(r.MultipartForm.File) == 0 {
return "", fmt.Errorf("no files")
}
password := r.FormValue("password")
if password != p.b.GetPassword() {
func (p *EmojyPlugin) FileSave(input *UploadReq) (string, error) {
if !p.b.CheckPassword("", input.Password) {
return "", fmt.Errorf("incorrect password")
}
for _, fileHeaders := range r.MultipartForm.File {
for _, fileHeader := range fileHeaders {
body, err := fileHeader.Open()
if err != nil {
return "", fmt.Errorf("error opening part %q: %s", fileHeader.Filename, err)
}
emojyFileName := fileHeader.Filename
file := input.Attachment
emojyFileName := file.Filename()
emojyName := strings.TrimSuffix(emojyFileName, filepath.Ext(emojyFileName))
if ok, _, _, _ := p.isKnownEmojy(emojyName); ok {
return "", fmt.Errorf("emojy already exists")
}
contentType := fileHeader.Header.Get("Content-Type")
contentType := file.MIMEHeader().Get("Content-Type")
if !strings.HasPrefix(contentType, "image") {
return "", fmt.Errorf("incorrect mime type - given: %s", contentType)
}
fullPath := filepath.Clean(filepath.Join(p.emojyPath, emojyFileName))
_ = os.MkdirAll(p.emojyPath, os.ModePerm)
log.Debug().Msgf("trying to create/open file: %s", fullPath)
file, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, os.ModePerm)
outFile, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, os.ModePerm)
if err != nil {
return "", err
}
defer file.Close()
_, err = io.Copy(file, body)
defer outFile.Close()
inFile, _ := file.ReadAll()
stream, _ := file.OpenReceiveStream()
_, err = outFile.Write(inFile)
_, err = io.Copy(outFile, stream)
if err != nil {
return "", err
}
return emojyFileName, nil
}
}
return "", fmt.Errorf("did not find file")
type EmojyReq struct {
Name string `in:"path=name"`
}
func (p *EmojyPlugin) handleEmojy(w http.ResponseWriter, r *http.Request) {
fname := chi.URLParam(r, "name")
contents, err := ioutil.ReadFile(path.Join(p.emojyPath, fname))
input := r.Context().Value(httpin.Input).(*EmojyReq)
contents, err := ioutil.ReadFile(path.Join(p.emojyPath, input.Name))
if err != nil {
w.WriteHeader(404)
out, _ := json.Marshal(struct{ err error }{err})

View File

@ -3,10 +3,9 @@ package fact
import (
"embed"
"fmt"
"github.com/ggicci/httpin"
"github.com/go-chi/chi/v5"
"html/template"
"net/http"
"strings"
)
//go:embed *.html
@ -15,26 +14,20 @@ var embeddedFS embed.FS
// Register any web URLs desired
func (p *FactoidPlugin) registerWeb() {
r := chi.NewRouter()
r.Post("/search", p.handleSearch)
r.HandleFunc("/req", p.serveQuery)
r.HandleFunc("/", p.serveQuery)
r.With(httpin.NewInput(SearchReq{})).
Post("/search", p.handleSearch)
r.Get("/", p.serveQuery)
p.b.GetWeb().RegisterWebName(r, "/factoid", "Factoid")
}
func linkify(text string) template.HTML {
parts := strings.Fields(text)
for i, word := range parts {
if strings.HasPrefix(word, "http") {
parts[i] = fmt.Sprintf("<a href=\"%s\">%s</a>", word, word)
}
}
return template.HTML(strings.Join(parts, " "))
type SearchReq struct {
Query string `in:"query"`
}
func (p *FactoidPlugin) handleSearch(w http.ResponseWriter, r *http.Request) {
query := r.FormValue("query")
input := r.Context().Value(httpin.Input).(*SearchReq)
entries, err := getFacts(p.db, query, "")
entries, err := getFacts(p.db, input.Query, "")
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, err)

View File

@ -45,9 +45,10 @@ func (p *LastPlugin) migrate() error {
_, err = tx.Exec(`create table if not exists last (
day integer,
channel string not null,
ts int not null,
who string not null,
message string not null,
time int not null,
nick string not null,
body string not null,
message_id string not null,
constraint last_key primary key (day, channel) on conflict replace
)`)
if err != nil {
@ -134,8 +135,8 @@ func (p *LastPlugin) recordLast(r bot.Request) bool {
}
_, err := p.db.Exec(
`insert into last values (?, ?, ?, ?, ?)`,
day.Unix(), ch, time.Now().Unix(), who, r.Msg.Body)
`insert into last (day, channel, time, body, nick, message_id) values (?, ?, ?, ?, ?, ?)`,
day.Unix(), ch, time.Now().Unix(), r.Msg.Body, who, r.Msg.ID)
if err != nil {
log.Error().Err(err).Msgf("Could not record last.")
}
@ -143,11 +144,13 @@ func (p *LastPlugin) recordLast(r bot.Request) bool {
}
type last struct {
Day int64
TS int64
Channel string
Who string
Message string
ID int64 `db:"id"`
Day int64 `db:"day"`
Time int64 `db:"time"`
Channel string `db:"channel"`
Nick string `db:"nick"`
Body string `db:"body"`
MessageID string `db:"message_id"`
}
func (p *LastPlugin) yesterdaysLast(ch string) (last, error) {
@ -189,6 +192,11 @@ func (p *LastPlugin) sayLast(c bot.Connector, chFrom, chTo string, force bool) {
}
return
}
msg := fmt.Sprintf(`%s killed the channel last night by saying "%s"`, l.Who, l.Message)
p.b.Send(c, bot.Message, chTo, msg)
msg := fmt.Sprintf(`%s killed the channel last night by saying "%s"`, l.Nick, l.Body)
guildID := p.c.Get("discord.guildid", "")
p.b.Send(c, bot.Message, chTo, msg, bot.MessageReference{
MessageID: l.MessageID,
ChannelID: l.Channel,
GuildID: guildID,
})
}

View File

@ -3,6 +3,7 @@ package meme
import (
"encoding/json"
"fmt"
"github.com/ggicci/httpin"
"net/http"
"net/url"
"sort"
@ -17,8 +18,10 @@ func (p *MemePlugin) registerWeb(c bot.Connector) {
r := chi.NewRouter()
r.HandleFunc("/slash", p.slashMeme(c))
r.Get("/img", p.img)
r.Put("/save/{name}", p.saveMeme)
r.Post("/add", p.saveMeme)
r.With(httpin.NewInput(SaveReq{})).
Put("/save/{name}", p.saveMeme)
r.With(httpin.NewInput(SaveReq{})).
Post("/add", p.saveMeme)
r.Delete("/rm/{name}", p.rmMeme)
r.Get("/edit/{name}", p.editMeme)
r.Get("/", p.webRoot)
@ -85,31 +88,33 @@ func (p *MemePlugin) rmMeme(w http.ResponseWriter, r *http.Request) {
mkCheckError(w)(err)
}
func (p *MemePlugin) saveMeme(w http.ResponseWriter, r *http.Request) {
name := chi.URLParam(r, "name")
if name == "" {
name = r.FormValue("name")
type SaveReq struct {
Name string `in:"path=name"`
Config string `in:"form=config"`
URL string `in:"form=url"`
}
func (p *MemePlugin) saveMeme(w http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*SaveReq)
checkError := mkCheckError(w)
formats := p.c.GetMap("meme.memes", defaultFormats)
formats[name] = r.FormValue("url")
formats[input.Name] = input.URL
err := p.c.SetMap("meme.memes", formats)
checkError(err)
config := r.FormValue("config")
if config == "" {
config = p.defaultFormatConfigJSON()
if input.Config == "" {
input.Config = p.defaultFormatConfigJSON()
}
configs := p.c.GetMap("meme.memeconfigs", map[string]string{})
configs[name] = config
configs[input.Name] = input.Config
err = p.c.SetMap("meme.memeconfigs", configs)
checkError(err)
meme := webResp{
Name: name,
URL: formats[name],
Config: configs[name],
Name: input.Name,
URL: formats[input.Name],
Config: configs[input.Name],
}
p.Show(meme).Render(r.Context(), w)

View File

@ -3,6 +3,7 @@ package secrets
import (
"encoding/json"
"fmt"
"github.com/ggicci/httpin"
"github.com/go-chi/chi/v5"
"github.com/jmoiron/sqlx"
"github.com/rs/zerolog/log"
@ -31,9 +32,10 @@ func New(b bot.Bot) bot.Plugin {
func (p *SecretsPlugin) registerWeb() {
r := chi.NewRouter()
r.HandleFunc("/add", p.handleRegister)
r.HandleFunc("/remove", p.handleRemove)
r.HandleFunc("/", p.handleIndex)
r.With(httpin.NewInput(RegisterReq{})).
Post("/add", p.handleRegister)
r.Delete("/remove", p.handleRemove)
r.Get("/", p.handleIndex)
p.b.GetWeb().RegisterWebName(r, "/secrets", "Secrets")
}
@ -71,14 +73,15 @@ func (p *SecretsPlugin) handleAll(w http.ResponseWriter, r *http.Request) {
p.sendKeys(w, r)
}
func (p *SecretsPlugin) handleRegister(w http.ResponseWriter, r *http.Request) {
if checkMethod(http.MethodPost, w, r) {
log.Debug().Msgf("failed post %s", r.Method)
return
type RegisterReq struct {
Key string `in:"form=key"`
Value string `in:"form=value"`
}
func (p *SecretsPlugin) handleRegister(w http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*RegisterReq)
checkError := mkCheckError(w)
key, value := r.FormValue("key"), r.FormValue("value")
err := p.c.RegisterSecret(key, value)
err := p.c.RegisterSecret(input.Key, input.Value)
if checkError(err) {
return
}
@ -86,9 +89,6 @@ func (p *SecretsPlugin) handleRegister(w http.ResponseWriter, r *http.Request) {
}
func (p *SecretsPlugin) handleRemove(w http.ResponseWriter, r *http.Request) {
if checkMethod(http.MethodDelete, w, r) {
return
}
checkError := mkCheckError(w)
b, err := io.ReadAll(r.Body)
if checkError(err) {