(Null)
This commit is contained in:
parent
aa2d04368e
commit
03c3c58811
4
.gitignore
vendored
4
.gitignore
vendored
@ -28,6 +28,10 @@ go.work.sum
|
||||
# env file
|
||||
.env
|
||||
|
||||
#sensitive config file and cred file
|
||||
config.json
|
||||
accounts.txt
|
||||
ircserver
|
||||
# Editor/IDE
|
||||
# .idea/
|
||||
# .vscode/
|
||||
|
||||
190
http.go
190
http.go
@ -1,19 +1,201 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type ModeResponse struct {
|
||||
Action string `json:"action"`
|
||||
Mode string `json:"mode"`
|
||||
Target string `json:"target"`
|
||||
Channel string `json:"channel"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
type KickResponse struct {
|
||||
Action string `json:"action"`
|
||||
Target string `json:"target"`
|
||||
Channel string `json:"channel"`
|
||||
Reason string `json:"reason"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func startHTTP(cfg Config) {
|
||||
htport := cfg.Webapiport
|
||||
http.HandleFunc("/admin/", handleAdmin)
|
||||
http.HandleFunc("/admin/kick", handleKick)
|
||||
http.HandleFunc("/admin/mode", handleModeAPI)
|
||||
http.HandleFunc("/admin/list", handleListAPI)
|
||||
http.HandleFunc("/admin/reloadmotd", handleMOTDreload)
|
||||
fmt.Printf("[web] starting API on port %d\n", htport)
|
||||
http.ListenAndServe(fmt.Sprintf(":%d", htport), nil)
|
||||
}
|
||||
func handleAdmin(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
func handleKick(w http.ResponseWriter, r *http.Request) {
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if !ok || !checkCredentials(user, pass) || !globalOps[user] {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "POST required", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
channelName := normalizeChannelName(r.FormValue("channel"))
|
||||
targetNick := r.FormValue("nick")
|
||||
reason := r.FormValue("reason")
|
||||
if reason == "" {
|
||||
reason = "Kicked via API"
|
||||
}
|
||||
|
||||
chMu.Lock()
|
||||
ch, ok := channels[channelName]
|
||||
chMu.Unlock()
|
||||
if !ok {
|
||||
http.Error(w, "No such channel", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
ch.mu.Lock()
|
||||
defer ch.mu.Unlock()
|
||||
|
||||
target, ok := ch.members[targetNick]
|
||||
if !ok {
|
||||
http.Error(w, "Target not in channel", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if globalOps[targetNick] {
|
||||
http.Error(w, "Cannot kick global operator", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
for _, member := range ch.members {
|
||||
member.fwrite(":server KICK %s %s :%s\r\n", channelName, targetNick, reason)
|
||||
}
|
||||
|
||||
// Remove target
|
||||
delete(ch.members, targetNick)
|
||||
delete(target.channels, channelName)
|
||||
|
||||
resp := KickResponse{
|
||||
Action: "kick",
|
||||
Target: targetNick,
|
||||
Channel: channelName,
|
||||
Reason: reason,
|
||||
Status: "ok",
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
func handleModeAPI(w http.ResponseWriter, r *http.Request) {
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if !ok || !checkCredentials(user, pass) || !globalOps[user] {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "POST required", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
channelName := normalizeChannelName(r.FormValue("channel"))
|
||||
mode := r.FormValue("mode")
|
||||
targetNick := r.FormValue("nick")
|
||||
|
||||
chMu.Lock()
|
||||
ch, ok := channels[channelName]
|
||||
chMu.Unlock()
|
||||
if !ok {
|
||||
http.Error(w, "No such channel", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
ch.mu.Lock()
|
||||
defer ch.mu.Unlock()
|
||||
|
||||
switch mode {
|
||||
case "+o":
|
||||
if targetNick != "" {
|
||||
ch.ops[targetNick] = true
|
||||
for _, member := range ch.members {
|
||||
member.fwrite(":api MODE %s +o %s\r\n", channelName, targetNick)
|
||||
}
|
||||
}
|
||||
case "-o":
|
||||
if targetNick != "" {
|
||||
if globalOps[targetNick] {
|
||||
http.Error(w, "Cannot remove global operator", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
delete(ch.ops, targetNick)
|
||||
for _, member := range ch.members {
|
||||
member.fwrite(":api MODE %s -o %s\r\n", channelName, targetNick)
|
||||
}
|
||||
}
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
http.Error(w, "Unknown MODE flag", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
resp := ModeResponse{
|
||||
Action: "mode",
|
||||
Mode: mode,
|
||||
Target: targetNick,
|
||||
Channel: channelName,
|
||||
Status: "ok",
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
type ChannelInfo struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Users int `json:"users"`
|
||||
}
|
||||
|
||||
func handleListAPI(w http.ResponseWriter, r *http.Request) {
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if !ok || !checkCredentials(user, pass) || !globalOps[user] {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
chMu.Lock()
|
||||
defer chMu.Unlock()
|
||||
|
||||
var list []ChannelInfo
|
||||
for _, ch := range channels {
|
||||
ch.mu.Lock()
|
||||
count := len(ch.members)
|
||||
desc := ch.description
|
||||
name := ch.name
|
||||
ch.mu.Unlock()
|
||||
|
||||
list = append(list, ChannelInfo{
|
||||
Name: name,
|
||||
Description: desc,
|
||||
Users: count,
|
||||
})
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(list); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
func handleMOTDreload(w http.ResponseWriter, r *http.Request) {
|
||||
user, pass, ok := r.BasicAuth()
|
||||
if !ok || !checkCredentials(user, pass) || !globalOps[user] {
|
||||
http.Error(w, "Unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
loadMOTD(motdFile)
|
||||
type htresp struct {
|
||||
Status string `json:"status"`
|
||||
}
|
||||
resp := htresp{
|
||||
Status: "ok",
|
||||
}
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
6
main.go
6
main.go
@ -64,11 +64,11 @@ func loadConfig() (*Config, error) {
|
||||
var conf Config
|
||||
jsdata, err := os.ReadFile("config.json")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(jsdata, &conf)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
return nil, err
|
||||
}
|
||||
for _, cfg := range conf.Channels {
|
||||
addChannel(cfg.Channel, cfg.Description)
|
||||
@ -78,7 +78,7 @@ func loadConfig() (*Config, error) {
|
||||
globalOps[cleanedNick] = true
|
||||
}
|
||||
motdFile = conf.Motd
|
||||
return conf.Port, nil
|
||||
return &conf, nil
|
||||
}
|
||||
func loadMOTD(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user