Compare commits

..

No commits in common. "def86a3c7e14cb31784d340ea218806ef0dcd92c" and "f602c2ec8d1c89435e0e9aea87039df46bcbd15e" have entirely different histories.

17 changed files with 351 additions and 299 deletions

View File

@ -63,12 +63,6 @@ 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,8 +11,6 @@ import (
"net/http"
"strings"
"time"
httpin_integration "github.com/ggicci/httpin/integration"
)
type Web struct {
@ -79,8 +77,6 @@ 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,7 +116,6 @@ 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) {
@ -142,20 +141,13 @@ 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,
}
}
}
data := &discordgo.MessageSend{
Content: message,
Embeds: embeds,
Files: files,
Reference: ref,
Content: message,
Embeds: embeds,
Files: files,
}
log.Debug().

6
go.mod
View File

@ -17,8 +17,7 @@ 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/ggicci/httpin v0.16.0
github.com/go-chi/chi/v5 v5.0.11
github.com/go-chi/chi/v5 v5.0.7
github.com/go-chi/httprate v0.7.0
github.com/gocolly/colly v1.2.0
github.com/google/uuid v1.3.0
@ -33,7 +32,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.4
github.com/stretchr/testify v1.8.2
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
@ -58,7 +57,6 @@ 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,13 +120,9 @@ 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.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
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/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=
@ -219,7 +215,6 @@ 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=
@ -257,7 +252,6 @@ 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=
@ -378,8 +372,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.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
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 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>
<div><span>ID</span><span>{ fmt.Sprintf("%d", entry.ID) }</span></div>
<div><span>Password</span><span>{ entry.Secret }:{ entry.Pass }</span></div>
}
templ (a *AdminPlugin) entries(items []PassEntry) {
@ -51,6 +51,7 @@ 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><div class=\"grid-x\"><div class=\"cell\" id=\"data\"></div></div></form></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></form><div class=\"grid-x\"><div class=\"cell\" id=\"data\"></div></div></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 style=\"margin-right: 2em\">ID</span><span>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<div><span>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))
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: 86}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 35, Col: 59}
}
_, 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 style=\"margin-right: 2em\">Password</span><span>")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</span></div><div><span>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: 77}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 36, Col: 50}
}
_, 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: 92}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 36, Col: 65}
}
_, 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\" name=\"id\" value=\"")
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" hx-target=\"#data\" hx-include=\"this,[name=&#39;password&#39;],[name=&#39;secret&#39;]\" 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: 54, Col: 57}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 55, 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: 62, Col: 22}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 63, 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: 78, Col: 38}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 79, 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: 78, Col: 61}
return templ.Error{Err: templ_7745c5c3_Err, FileName: `plugins/admin/admin.templ`, Line: 79, Col: 61}
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
if templ_7745c5c3_Err != nil {

View File

@ -4,12 +4,13 @@ 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"
@ -20,15 +21,8 @@ func (p *AdminPlugin) registerWeb() {
r.HandleFunc("/", p.handleVars)
p.bot.GetWeb().RegisterWebName(r, "/vars", "Variables")
r = chi.NewRouter()
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("/verify", p.handleAppPassCheck)
r.HandleFunc("/api", p.handleAppPassAPI)
r.HandleFunc("/", p.handleAppPass)
p.bot.GetWeb().RegisterWebName(r, "/apppass", "App Pass")
}
@ -38,8 +32,8 @@ func (p *AdminPlugin) handleAppPass(w http.ResponseWriter, r *http.Request) {
}
type PassEntry struct {
ID int64 `json:"id" in:"form=id;query=password"`
Secret string `json:"secret" in:"form=secret;query=password"`
ID int64 `json:"id"`
Secret string `json:"secret"`
// Should be null unless inserting a new entry
Pass string `json:"pass"`
@ -63,117 +57,107 @@ func (p *PassEntry) Compare(pass string) bool {
return true
}
type AppPassCheckReq struct {
Secret string `json:"secret"`
Password string `json:"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) {
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)
}
}
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))
input.Password = query.Get("password")
input.PassEntry.ID, _ = strconv.ParseInt(query.Get("id"), 10, 64)
input.PassEntry.Secret = query.Get("secret")
func (p *AdminPlugin) handleAppPassAPI(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
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")
}
log.Printf("checkAPIInput: %#v", input)
if input.PassEntry.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 == "" {
writeErr(r.Context(), w, fmt.Errorf("missing secret"))
return nil
}
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
}
if string(input.PassEntry.Pass) == "" {
c := 10
b := make([]byte, c)
_, err := rand.Read(b)
if req.Password == "" || !p.bot.CheckPassword(req.PassEntry.Secret, req.Password) {
writeErr(r.Context(), w, fmt.Errorf("missing or incorrect password"))
return
}
switch r.Method {
case http.MethodPut:
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 {
fmt.Println("error:", err)
writeErr(r.Context(), w, err)
return
}
input.PassEntry.Pass = fmt.Sprintf("%x", md5.Sum(b))
}
q := `insert into apppass (secret, encoded_pass, cost) values (?, ?, ?)`
input.PassEntry.EncodePass()
id, err := res.LastInsertId()
if err != nil {
writeErr(r.Context(), w, err)
return
}
req.PassEntry.ID = id
p.showPassword(req.PassEntry).Render(r.Context(), w)
return
case http.MethodDelete:
check := bcrypt.CompareHashAndPassword(input.PassEntry.encodedPass, []byte(input.PassEntry.Pass))
log.Debug().
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, input.PassEntry.Secret, input.PassEntry.encodedPass, input.PassEntry.Cost)
if err != nil {
writeErr(r.Context(), w, err)
return
}
id, err := res.LastInsertId()
if err != nil {
writeErr(r.Context(), w, err)
return
}
input.PassEntry.ID = id
p.showPassword(input.PassEntry).Render(r.Context(), w)
}
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, 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
if req.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)
if err != nil {
writeErr(r.Context(), w, err)
return
}
}
q := `select id,secret from apppass where secret = ?`
passEntries := []PassEntry{}
err := p.db.Select(&passEntries, q, input.PassEntry.Secret)
err := p.db.Select(&passEntries, q, req.PassEntry.Secret)
if err != nil {
writeErr(r.Context(), w, err)
return

View File

@ -3,8 +3,10 @@ package counter
import (
"encoding/json"
"fmt"
"github.com/ggicci/httpin"
"io"
"net/http"
"net/url"
"strconv"
"time"
"github.com/go-chi/chi/v5"
@ -21,48 +23,34 @@ func (p *CounterPlugin) registerWeb() {
dur := time.Duration(seconds) * time.Second
subrouter := chi.NewRouter()
subrouter.Use(httprate.LimitByIP(requests, dur))
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))
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))
r.Mount("/", subrouter)
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("/users/{user}/items/{item}/increment", p.incHandler(1))
r.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) {
input := r.Context().Value(httpin.Input).(*CounterChangeReq)
if !p.b.CheckPassword("", input.Password) {
userName, _ := url.QueryUnescape(chi.URLParam(r, "user"))
itemName, _ := url.QueryUnescape(chi.URLParam(r, "item"))
pass := r.FormValue("password")
if !p.b.CheckPassword("", pass) {
w.WriteHeader(401)
fmt.Fprintf(w, "error")
return
}
item, err := p.delta(input.UserName, input.Item, "", delta)
item, err := p.delta(userName, itemName, "", delta)
if err != nil {
w.WriteHeader(500)
fmt.Fprintf(w, "error")
return
}
p.renderItem(input.UserName, item).Render(r.Context(), w)
p.renderItem(userName, item).Render(r.Context(), w)
}
}
@ -115,11 +103,13 @@ 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) {
input := r.Context().Value(httpin.Input).(*CounterChangeReq)
if input.Delta == 0 {
input.Delta = direction
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
} else {
input.Delta = input.Delta * direction
delta = delta * direction
}
secret, pass, ok := r.BasicAuth()
@ -137,12 +127,15 @@ 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 input.Body.Message != "" {
personalMsg = fmt.Sprintf("\nMessage: %s", input.Body.Message)
if inputMsg, ok := postData["message"]; ok {
personalMsg = fmt.Sprintf("\nMessage: %s", inputMsg)
}
if _, err := p.delta(input.UserName, input.Item, personalMsg, input.Delta*direction); err != nil {
if _, err := p.delta(userName, itemName, personalMsg, delta*direction); err != nil {
log.Error().Err(err).Msg("error finding item")
w.WriteHeader(400)
j, _ := json.Marshal(struct {

104
plugins/counter/index.html Normal file
View File

@ -0,0 +1,104 @@
<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,7 +12,6 @@ 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>
@ -20,13 +19,12 @@ templ (p *EmojyPlugin) uploadIndex() {
</div>
<div class="cell">
<label>File
<input type="file" name="attachment" />
<input type="file" />
</label>
</div>
<div class="cell">
<button class="button" type="submit">Submit</button>
<button class="button" hx-post="/emojy/upload">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><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>")
_, 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>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}

View File

@ -4,7 +4,6 @@ import (
"embed"
"encoding/json"
"fmt"
"github.com/ggicci/httpin"
"io"
"io/ioutil"
"net/http"
@ -24,10 +23,8 @@ func (p *EmojyPlugin) registerWeb() {
r := chi.NewRouter()
r.HandleFunc("/all", p.handleAll)
r.HandleFunc("/allFiles", p.handleAllFiles)
r.With(httpin.NewInput(UploadReq{})).
Post("/upload", p.handleUpload)
r.With(httpin.NewInput(EmojyReq{})).
HandleFunc("/file/{name}", p.handleEmojy)
r.HandleFunc("/upload", p.handleUpload)
r.HandleFunc("/file/{name}", p.handleEmojy)
r.HandleFunc("/stats", p.handleStats)
r.HandleFunc("/list", p.handleList)
r.HandleFunc("/new", p.handleUploadForm)
@ -101,15 +98,8 @@ 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) {
input := r.Context().Value(httpin.Input).(*UploadReq)
log.Printf("handleUpload: %#v", input)
newFilePath, err := p.FileSave(input)
newFilePath, err := p.FileSave(r)
if err != nil {
log.Error().Err(err).Msgf("could not upload file")
w.WriteHeader(500)
@ -121,46 +111,60 @@ func (p *EmojyPlugin) handleUpload(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "success")
}
func (p *EmojyPlugin) FileSave(input *UploadReq) (string, error) {
if !p.b.CheckPassword("", input.Password) {
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() {
return "", fmt.Errorf("incorrect password")
}
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")
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
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")
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)
if err != nil {
return "", err
}
defer file.Close()
_, err = io.Copy(file, body)
if err != nil {
return "", err
}
return emojyFileName, nil
}
}
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)
outFile, err := os.OpenFile(fullPath, os.O_WRONLY|os.O_CREATE, os.ModePerm)
if err != nil {
return "", err
}
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
}
type EmojyReq struct {
Name string `in:"path=name"`
return "", fmt.Errorf("did not find file")
}
func (p *EmojyPlugin) handleEmojy(w http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*EmojyReq)
contents, err := ioutil.ReadFile(path.Join(p.emojyPath, input.Name))
fname := chi.URLParam(r, "name")
contents, err := ioutil.ReadFile(path.Join(p.emojyPath, fname))
if err != nil {
w.WriteHeader(404)
out, _ := json.Marshal(struct{ err error }{err})

View File

@ -3,9 +3,10 @@ package fact
import (
"embed"
"fmt"
"github.com/ggicci/httpin"
"github.com/go-chi/chi/v5"
"html/template"
"net/http"
"strings"
)
//go:embed *.html
@ -14,20 +15,26 @@ var embeddedFS embed.FS
// Register any web URLs desired
func (p *FactoidPlugin) registerWeb() {
r := chi.NewRouter()
r.With(httpin.NewInput(SearchReq{})).
Post("/search", p.handleSearch)
r.Get("/", p.serveQuery)
r.Post("/search", p.handleSearch)
r.HandleFunc("/req", p.serveQuery)
r.HandleFunc("/", p.serveQuery)
p.b.GetWeb().RegisterWebName(r, "/factoid", "Factoid")
}
type SearchReq struct {
Query string `in:"query"`
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, " "))
}
func (p *FactoidPlugin) handleSearch(w http.ResponseWriter, r *http.Request) {
input := r.Context().Value(httpin.Input).(*SearchReq)
query := r.FormValue("query")
entries, err := getFacts(p.db, input.Query, "")
entries, err := getFacts(p.db, query, "")
if err != nil {
w.WriteHeader(500)
fmt.Fprint(w, err)

View File

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

View File

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

View File

@ -3,7 +3,6 @@ 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"
@ -32,10 +31,9 @@ func New(b bot.Bot) bot.Plugin {
func (p *SecretsPlugin) registerWeb() {
r := chi.NewRouter()
r.With(httpin.NewInput(RegisterReq{})).
Post("/add", p.handleRegister)
r.Delete("/remove", p.handleRemove)
r.Get("/", p.handleIndex)
r.HandleFunc("/add", p.handleRegister)
r.HandleFunc("/remove", p.handleRemove)
r.HandleFunc("/", p.handleIndex)
p.b.GetWeb().RegisterWebName(r, "/secrets", "Secrets")
}
@ -73,15 +71,14 @@ func (p *SecretsPlugin) handleAll(w http.ResponseWriter, r *http.Request) {
p.sendKeys(w, r)
}
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)
if checkMethod(http.MethodPost, w, r) {
log.Debug().Msgf("failed post %s", r.Method)
return
}
checkError := mkCheckError(w)
err := p.c.RegisterSecret(input.Key, input.Value)
key, value := r.FormValue("key"), r.FormValue("value")
err := p.c.RegisterSecret(key, value)
if checkError(err) {
return
}
@ -89,6 +86,9 @@ 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) {