mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-17 10:56:24 -07:00
Update IP ban interface for new gcsql API
This commit is contained in:
parent
efccbdd001
commit
34688190e2
8 changed files with 216 additions and 146 deletions
|
@ -3,6 +3,7 @@ package gcsql
|
|||
import (
|
||||
"database/sql"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Ban interface {
|
||||
|
@ -30,6 +31,45 @@ func CheckIPBan(ip string, boardID int) (*IPBan, error) {
|
|||
return &ban, nil
|
||||
}
|
||||
|
||||
func GetIPBans(boardID int, limit int, onlyActive bool) ([]IPBan, error) {
|
||||
query := `SELECT
|
||||
id, staff_id, board_id, banned_for_post_id, copy_post_text, is_thread_ban,
|
||||
is_active, ip, issued_at, appeal_at, expires_at, permanent, staff_note,
|
||||
message, can_appeal
|
||||
FROM DBPREFIXip_ban`
|
||||
if boardID > 0 {
|
||||
query += " WHERE board_id = ?"
|
||||
}
|
||||
query += " LIMIT " + strconv.Itoa(limit)
|
||||
var rows *sql.Rows
|
||||
var err error
|
||||
if boardID > 0 {
|
||||
rows, err = QuerySQL(query, boardID)
|
||||
} else {
|
||||
rows, err = QuerySQL(query)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var bans []IPBan
|
||||
for rows.Next() {
|
||||
var ban IPBan
|
||||
if err = rows.Scan(
|
||||
&ban.ID, &ban.StaffID, &ban.BoardID, &ban.BannedForPostID, &ban.CopyPostText, &ban.IsThreadBan,
|
||||
&ban.IsActive, &ban.IP, &ban.IssuedAt, &ban.AppealAt, &ban.ExpiresAt, &ban.Permanent, &ban.StaffNote,
|
||||
&ban.Message, &ban.CanAppeal,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if onlyActive && !ban.IsActive {
|
||||
continue
|
||||
}
|
||||
bans = append(bans, ban)
|
||||
}
|
||||
return bans, nil
|
||||
}
|
||||
|
||||
// IsGlobalBan returns true if BoardID is a nil int, meaning they are banned on all boards, as opposed to a specific one
|
||||
func (ipb IPBan) IsGlobalBan() bool {
|
||||
return ipb.BoardID == nil
|
||||
|
@ -99,7 +139,9 @@ func CheckFilenameBan(filename string, boardID int) (*FilenameBan, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
func CheckFileBan(checksum string, boardID int) (*FileBan, error) {
|
||||
// CheckFileChecksumBan checks to see if the given checksum is banned on the given boardID, or on all boards.
|
||||
// It returns the ban info (or nil if it is not banned) and any errors
|
||||
func CheckFileChecksumBan(checksum string, boardID int) (*FileBan, error) {
|
||||
const query = `SELECT
|
||||
id, board_id, staff_id, staff_note, issued_at, checksum
|
||||
FROM DBPREFIXfile_ban
|
||||
|
@ -117,6 +159,44 @@ func CheckFileBan(checksum string, boardID int) (*FileBan, error) {
|
|||
return &ban, err
|
||||
}
|
||||
|
||||
func GetChecksumBans(boardID int, limit int) ([]FileBan, error) {
|
||||
query := `SELECT
|
||||
id, board_id, staff_id, staff_note, issued_at, checksum
|
||||
FROM DBPREFIXfile_ban`
|
||||
if boardID > 0 {
|
||||
query += " WHERE board_id = ?"
|
||||
}
|
||||
query += " LIMIT " + strconv.Itoa(limit)
|
||||
var rows *sql.Rows
|
||||
var err error
|
||||
if boardID > 0 {
|
||||
rows, err = QuerySQL(query, boardID)
|
||||
} else {
|
||||
rows, err = QuerySQL(query)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var bans []FileBan
|
||||
for rows.Next() {
|
||||
var ban FileBan
|
||||
if err = rows.Scan(
|
||||
&ban.ID, &ban.BoardID, &ban.StaffID, &ban.StaffNote, &ban.IssuedAt, &ban.Checksum,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bans = append(bans, ban)
|
||||
}
|
||||
return bans, nil
|
||||
}
|
||||
|
||||
func (fb *FileBan) IsGlobalBan() bool {
|
||||
return fb.BoardID == nil
|
||||
}
|
||||
|
||||
// DeleteFileBanByID deletes the ban, given the id column value
|
||||
func DeleteFileBanByID(id int) error {
|
||||
_, err := ExecSQL("DELETE FROM DBPREFIXfile_ban WHERE id = ?", id)
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -103,6 +103,25 @@ func GetBoardFromID(id int) (*Board, error) {
|
|||
return board, err
|
||||
}
|
||||
|
||||
// GetBoardURIs gets a list of all existing board URIs
|
||||
func GetBoardURIs() (URIS []string, err error) {
|
||||
const sql = `SELECT uri FROM DBPREFIXboards`
|
||||
rows, err := QuerySQL(sql)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var uris []string
|
||||
for rows.Next() {
|
||||
var uri string
|
||||
if err = rows.Scan(&uri); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uris = append(uris, uri)
|
||||
}
|
||||
return uris, nil
|
||||
}
|
||||
|
||||
// ResetBoardSectionArrays is run when the board list needs to be changed
|
||||
// (board/section is added, deleted, etc)
|
||||
func ResetBoardSectionArrays() error {
|
||||
|
|
|
@ -115,7 +115,7 @@ func DeactivateStaff(username string) error {
|
|||
return s.SetActive(false)
|
||||
}
|
||||
|
||||
func getStaffUsernameFromID(id int) (string, error) {
|
||||
func GetStaffUsernameFromID(id int) (string, error) {
|
||||
const query = `SELECT username FROM DBPREFIXstaff WHERE id = ?`
|
||||
var username string
|
||||
err := QueryRowSQL(query, interfaceSlice(id), interfaceSlice(&username))
|
||||
|
|
|
@ -102,7 +102,7 @@ func (wf *Wordfilter) OnBoard(dir string) bool {
|
|||
}
|
||||
|
||||
func (wf *Wordfilter) StaffName() string {
|
||||
staff, err := getStaffUsernameFromID(wf.StaffID)
|
||||
staff, err := GetStaffUsernameFromID(wf.StaffID)
|
||||
if err != nil {
|
||||
return "?"
|
||||
}
|
||||
|
|
|
@ -159,6 +159,17 @@ var funcMap = template.FuncMap{
|
|||
"isBanned": func(ban *gcsql.IPBan, board string) bool {
|
||||
return ban.IsActive && ban.BoardID != nil
|
||||
},
|
||||
"getBoardDirFromID": func(id int) string {
|
||||
dir, _ := gcsql.GetBoardDir(id)
|
||||
return dir
|
||||
},
|
||||
"getStaffNameFromID": func(id int) string {
|
||||
username, err := gcsql.GetStaffUsernameFromID(id)
|
||||
if err != nil {
|
||||
return "?"
|
||||
}
|
||||
return username
|
||||
},
|
||||
"getCatalogThumbnail": func(img string) string {
|
||||
return gcutil.GetThumbnailPath("catalog", img)
|
||||
},
|
||||
|
|
|
@ -211,134 +211,82 @@ var actions = []Action{
|
|||
return manageRecentsBuffer.String(), nil
|
||||
},
|
||||
},
|
||||
/* {
|
||||
ID: "filebans",
|
||||
Title: "File bans",
|
||||
{
|
||||
ID: "checksumbans",
|
||||
Title: "File checksum bans",
|
||||
Permissions: ModPerms,
|
||||
JSONoutput: OptionalJSON,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool) (interface{}, error) {
|
||||
var err error
|
||||
fileBanType := request.PostForm.Get("bantype")
|
||||
delFnbStr := request.Form.Get("delfnb")
|
||||
if delFnbStr != "" {
|
||||
var delFilenameBanID int
|
||||
if delFilenameBanID, err = strconv.Atoi(delFnbStr); err != nil {
|
||||
errorEv.Err(err).
|
||||
Str("delfnb", delFnbStr).Caller().Send()
|
||||
return "", err
|
||||
}
|
||||
if err = gcsql.DeleteFilenameBanByID(delFilenameBanID); err != nil {
|
||||
errorEv.Err(err).
|
||||
Int("delfnb", delFilenameBanID).Caller().Send()
|
||||
return "", err
|
||||
}
|
||||
infoEv.Int("delFilenameBan", delFilenameBanID).Send()
|
||||
}
|
||||
delCsbStr := request.Form.Get("delcsb")
|
||||
if delCsbStr != "" {
|
||||
var delChecksumBanID int
|
||||
if delChecksumBanID, err = strconv.Atoi(delCsbStr); err != nil {
|
||||
errorEv.Err(err).
|
||||
Str("delcsb", delCsbStr).Send()
|
||||
return "", err
|
||||
}
|
||||
if err = gcsql.DeleteFileBanByID(delChecksumBanID); err != nil {
|
||||
errorEv.Err(err).
|
||||
Int("delcsb", delChecksumBanID).Send()
|
||||
return "", err
|
||||
}
|
||||
InfoEv.Int("delChecksumBan", delChecksumBanID).Send()
|
||||
}
|
||||
switch fileBanType {
|
||||
case "filename":
|
||||
// filename form used
|
||||
filename := request.PostForm.Get("filename")
|
||||
isWildcard := request.PostForm.Get("iswildcard") == "on"
|
||||
board := request.PostForm.Get("board")
|
||||
staffNote := request.PostForm.Get("staffnote")
|
||||
if filename == "" {
|
||||
err = errors.New("missing filename field in filename ban creation")
|
||||
errorEv.Err(err).Send()
|
||||
return "", err
|
||||
}
|
||||
if err = gcsql.CreateFileNameBan(filename, isWildcard, staff.Username, staffNote, board); err != nil {
|
||||
errorEv.Err(err).
|
||||
Str("filename", filename).
|
||||
Bool("iswildcard", isWildcard).
|
||||
Str("board", board).
|
||||
Str("staffnote", staffNote).Send()
|
||||
return "", err
|
||||
}
|
||||
gcutil.LogInfo().
|
||||
Str("action", "filebans").
|
||||
Str("staff", staff.Username).
|
||||
Str("newBanType", "filename").Send()
|
||||
case "checksum":
|
||||
// file checksum form used
|
||||
checksum := request.PostForm.Get("checksum")
|
||||
board := request.PostForm.Get("board")
|
||||
staffNote := request.PostForm.Get("staffnote")
|
||||
if checksum == "" {
|
||||
err = errors.New("missing checksum field in filename ban creation")
|
||||
errorEv.Err(err).Send()
|
||||
return "", err
|
||||
}
|
||||
if err = gcsql.CreateFileBan(checksum, staff.Username, staffNote, board); err != nil {
|
||||
errorEv.Err(err).
|
||||
Str("checksum", checksum).
|
||||
Str("board", board).
|
||||
Str("staffnote", staffNote).Send()
|
||||
return "", err
|
||||
}
|
||||
infoEv.Str("newBanType", "checksum").Send()
|
||||
case "":
|
||||
// no POST data sent
|
||||
default:
|
||||
err = fmt.Errorf(`invalid bantype value %q, valid values are "filename" and "checksum"`, fileBanType)
|
||||
errorEv.Err(err).Caller().Send()
|
||||
return "", err
|
||||
}
|
||||
|
||||
filenameBans, err := gcsql.GetFilenameBans("", false)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
checksumBans, err := gcsql.GetFileChecksumBans("")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if wantsJSON {
|
||||
return map[string]interface{}{
|
||||
"filenameBans": filenameBans,
|
||||
"checksumBans": checksumBans,
|
||||
}, nil
|
||||
}
|
||||
|
||||
boardURIs, err := gcsql.GetBoardUris()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
manageBansBuffer := bytes.NewBufferString("")
|
||||
if err = serverutil.MinifyTemplate(gctemplates.ManageFileBans, map[string]interface{}{
|
||||
"webroot": config.GetSystemCriticalConfig().WebRoot,
|
||||
"filenameBans": filenameBans,
|
||||
"checksumBans": checksumBans,
|
||||
"currentStaff": staff.Username,
|
||||
"boardURIs": boardURIs,
|
||||
}, manageBansBuffer, "text/html"); err != nil {
|
||||
errorEv.Err(err).Str("template", "manage_filebans.html").Caller().Send()
|
||||
return "", errors.New("failed executing file ban management page template: " + err.Error())
|
||||
}
|
||||
return manageBansBuffer.String(), nil
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool, infoEv, errEv *zerolog.Event) (output interface{}, err error) {
|
||||
return "", gcutil.ErrNotImplemented
|
||||
},
|
||||
}, */
|
||||
},
|
||||
{
|
||||
ID: "ipbans",
|
||||
ID: "bans",
|
||||
Title: "IP Bans",
|
||||
Permissions: ModPerms,
|
||||
JSONoutput: OptionalJSON,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request, staff *gcsql.Staff, wantsJSON bool, infoEv *zerolog.Event, errEv *zerolog.Event) (output interface{}, err error) {
|
||||
return "", gcutil.ErrNotImplemented
|
||||
var outputStr string
|
||||
ip := request.FormValue("ip")
|
||||
postid := request.FormValue("postid")
|
||||
ban := gcsql.IPBan{
|
||||
BoardID: new(int),
|
||||
}
|
||||
*ban.BoardID = 32
|
||||
|
||||
if request.FormValue("do") == "add" {
|
||||
//
|
||||
}
|
||||
|
||||
boardIDstr := request.FormValue("boardid")
|
||||
var boardid int
|
||||
if boardIDstr != "" {
|
||||
if boardid, err = strconv.Atoi(boardIDstr); err != nil {
|
||||
errEv.Err(err).
|
||||
Str("boardid", boardIDstr).Caller().Send()
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
filterBoardIDstr := request.FormValue("filterboardid")
|
||||
var filterBoardID int
|
||||
if filterBoardIDstr != "" {
|
||||
if filterBoardID, err = strconv.Atoi(filterBoardIDstr); err != nil {
|
||||
errEv.Err(err).
|
||||
Str("filterboardid", filterBoardIDstr).Caller().Send()
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
limitStr := request.FormValue("limit")
|
||||
limit := 200
|
||||
if limitStr != "" {
|
||||
if limit, err = strconv.Atoi(limitStr); err != nil {
|
||||
errEv.Err(err).
|
||||
Str("limit", limitStr).Caller().Send()
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
banlist, err := gcsql.GetIPBans(filterBoardID, limit, true)
|
||||
if err != nil {
|
||||
errEv.Err(err).Msg("Error getting ban list")
|
||||
err = errors.New("Error getting ban list: " + err.Error())
|
||||
return "", err
|
||||
}
|
||||
manageBansBuffer := bytes.NewBufferString("")
|
||||
|
||||
if err = serverutil.MinifyTemplate(gctemplates.ManageBans, map[string]interface{}{
|
||||
"systemCritical": config.GetSystemCriticalConfig(),
|
||||
"banlist": banlist,
|
||||
"allBoards": gcsql.AllBoards,
|
||||
"boardid": boardid,
|
||||
"ip": ip,
|
||||
"postid": postid,
|
||||
"filterboardid": filterBoardID,
|
||||
}, manageBansBuffer, "text/html"); err != nil {
|
||||
errEv.Err(err).Str("template", "manage_bans.html").Caller().Send()
|
||||
return "", errors.New("Error executing ban management page template: " + err.Error())
|
||||
}
|
||||
outputStr += manageBansBuffer.String()
|
||||
return outputStr, nil
|
||||
},
|
||||
},
|
||||
/* {
|
||||
|
|
|
@ -129,7 +129,7 @@ func checkFilenameBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.B
|
|||
}
|
||||
|
||||
func checkChecksumBan(upload *gcsql.Upload, post *gcsql.Post, postBoard *gcsql.Board, writer http.ResponseWriter, request *http.Request) bool {
|
||||
fileBan, err := gcsql.CheckFileBan(upload.Checksum, postBoard.ID)
|
||||
fileBan, err := gcsql.CheckFileChecksumBan(upload.Checksum, postBoard.ID)
|
||||
if err != nil {
|
||||
gcutil.LogError(err).
|
||||
Str("IP", post.IP).
|
||||
|
|
|
@ -1,32 +1,44 @@
|
|||
<form method="POST" action="/manage?action=bans">
|
||||
<input type="hidden" name="do" value="add" />
|
||||
<b>User filter:</b><br />
|
||||
<h2>Add IP ban</h2>
|
||||
<table>
|
||||
<tr><th>IP address</th><td><input type="text" name="ip" value="{{.post.IP}}" /></td></tr>
|
||||
<tr><th></th><td>"192.168.1.36" will ban posts from that IP address<br />
|
||||
"192.168" will block all IPs starting with 192.168<br /></td></tr>
|
||||
<tr><th>Name!Tripcode</th><td><input type="text" name="name" value="{{if ne .post.Name ""}}{{.post.Name}}!{{.post.Tripcode}}{{end}}"/> <label>Regex<input type="checkbox" name="nameregex" /></label></td></tr>
|
||||
<tr><th>Ban filename</th><td><input type="text" name="filename" value="{{.post.FilenameOriginal}}"/></td></tr>
|
||||
<tr><th>Ban file checksum</th><td><input type="text" name="checksum" value="{{.post.FileChecksum}}" /></td></tr>
|
||||
</table><br /><hr />
|
||||
|
||||
<b>Ban info</b><br />
|
||||
<table>
|
||||
<tr><th>Duration</th><td><input type="text" name="duration" /></td></tr>
|
||||
<tr><th></th><td>e.g. '1y2mo3w4d5h6m7s',<br />'1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds',<br /> or 'forever', '0', or '' for a permaban</td></tr>
|
||||
<tr><th>Ban type</th><td><label>Image ban <input type="checkbox" name="imageban" /></label><br />
|
||||
<label>Thread starting ban <input type="checkbox" name="threadban" /></label><br />
|
||||
<label>Full ban (overrides the above) <input type="checkbox" name="fullban" /></label></tr>
|
||||
<tr><th>Boards</th><td><input type="text" name="boards" /></td></tr>
|
||||
<tr><th></th><td>Comma-separated list of boards (e.g. board1,board2,board3) or blank for all boards</td></tr>
|
||||
<tr><th>Reason</th><td><textarea name="reason" rows="5" cols="30"></textarea></td></tr>
|
||||
<tr><th>Staff note</th><td><input type="text" name="staffnote" /></td></tr>
|
||||
<tr><th></th><td>e.g. '1y2mo3w4d5h6m7s',<br />'1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds'<br/>Optional if "Permanent" is checked, required otherwise</td></tr>
|
||||
<tr><th>Permanent</th><td><input type="checkbox" name="permanent" id="permanent" {{with $.permanent}}{{if eq $.permanent "on"}}checked{{end}}{{end}}> (overrides the duration)</td></tr>
|
||||
<tr><th>Appeal wait time</th><td><input type="text" name="appealwait" id="appealwait"></td></tr>
|
||||
<tr><th></th><td>Same syntax as above, but optional.</td></tr>
|
||||
<tr><th>Thread starting ban</th><td><input type="checkbox" name="threadban" /></td></tr>
|
||||
{{with $.bannedForPostID}}<tr><th>Banned for post ID</th><td>{{$.bannedForPostID}}</td></tr>{{end}}
|
||||
<tr><th>Board</th><td><select name="boardid" id="boardid">
|
||||
<option value="0">All boards</option>
|
||||
{{- range $b, $board := $.allBoards -}}
|
||||
<option value="{{$board.ID}}" {{if eq $.boardid $board.ID}}selected{{end}}>/{{$board.Dir}}/ - {{$board.Title}}</option>
|
||||
{{- end -}}
|
||||
</select></td></tr>
|
||||
<tr><th>Reason</th><td><textarea name="reason" rows="5" cols="30" placeholder="Message to be displayed to the banned user"></textarea></td></tr>
|
||||
<tr><th>Staff note</th><td><textarea name="staffnote" rows="5" cols="30" placeholder="Private note that only staff can see"></textarea></td></tr>
|
||||
</table>
|
||||
<input type="submit" value="Ban user" />
|
||||
<input type="submit" value="Ban user" /> <input type="button" name="docancel" value="Cancel" onclick="window.location = './manage?action=bans'; return false"/>
|
||||
</form>
|
||||
|
||||
<h2 class="manage-header">Banlist</h2>
|
||||
<table>
|
||||
<tr><th>IP</th><th>Name!Tripcode</th><th>Reason</th><th>Staff note</th><th>Boards</th><th>Staff</th><th>Set</th><th>Expires</th><th>Permaban</th></tr>
|
||||
{{range $b, $ban := $.banlist}} <tr><td>{{$ban.IP}}</td><td>{{$ban.Name}}</td><td>{{$ban.Reason}}</td><td>{{$ban.StaffNote}}</td><td>{{if eq $ban.Boards ""}}<i>all boards</i>{{else}}{{$ban.Boards}}{{end}}</td><td>{{$ban.Staff}}</td><td>{{$ban.Timestamp}}</td><td>{{if $ban.Permaban}}never{{else}}{{$ban.Expires}}{{end}}</td><td>{{$ban.Permaban}}</td></tr>
|
||||
<table border="1">
|
||||
<tr><th>IP</th><th>Board</th><th>Reason</th><th>Staff</th><th>Staff note</th><th>Banned post text</th><th>Set</th><th>Expires</th><th>Appeal at</th></tr>
|
||||
{{range $_, $ban := $.banlist -}}
|
||||
<tr>
|
||||
<td>{{$ban.IP}}</td>
|
||||
<td>{{if not $ban.BoardID}}<i>all</i>{{else}}/{{getBoardDirFromID $ban.BoardID}}/{{end}}</td>
|
||||
<td>{{$ban.Message}}</td>
|
||||
<td>{{getStaffNameFromID $ban.StaffID}}</td>
|
||||
<td>{{$ban.StaffNote}}</td>
|
||||
<td>{{if not $ban.BannedForPostID}}<i>N/A</i>{{else}}{{$ban.CopyPostText}}{{end}}</td>
|
||||
<td>{{formatTimestamp $ban.IssuedAt}}</td>
|
||||
<td>
|
||||
{{- if $ban.Permanent}}<i>Never</i>{{else}}{{formatTimestamp $ban.ExpiresAt}}{{end -}}
|
||||
</td>
|
||||
<td>
|
||||
{{- if $ban.CanAppeal}}{{formatTimestamp $ban.AppealAt}}{{else}}<i>Never</i>{{end -}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}</table>
|
Loading…
Add table
Add a link
Reference in a new issue