mirror of
https://github.com/Eggbertx/gochan.git
synced 2025-08-18 07:36:24 -07:00
Mostly work on banning
If a user is banned, they are redirected to the ban page with all the information, but the appeal form doesn't work (yet) In the next couple commits I'm going to work on actually submitting bans
This commit is contained in:
parent
01877937eb
commit
ad9d0989b2
14 changed files with 210 additions and 314 deletions
|
@ -75,3 +75,7 @@ div#recent-posts-header {
|
|||
box-shadow: 0px 2px 2px 3px #101010;
|
||||
border-radius: 8px 8px 8px 8px;
|
||||
margin-bottom: 8px; }
|
||||
|
||||
.postblock {
|
||||
background-color: #202020;
|
||||
font-weight: 700; }
|
||||
|
|
|
@ -9,89 +9,6 @@ function addStaffButtons() {
|
|||
$jq("input[value=Delete]").after("<input type=\"submit\" name=\"Ban\" value=\"Ban\" onclick=\"alert('Bans not yet implemented'); return false;\" />")
|
||||
}
|
||||
|
||||
function banPage() {
|
||||
switch(getArg("type")) {
|
||||
case "ip":
|
||||
$jq("div#.ban-type-div#ip").css({"display":"inline"})
|
||||
$jq("div#.ban-type-div#name").css({"display":"none"})
|
||||
$jq("input[type=hidden][name=type]").attr("value", "ip")
|
||||
break;
|
||||
case "name-tripcode":
|
||||
$jq("div#.ban-type-div#ip").css({"display":"none"})
|
||||
$jq("div#.ban-type-div#name").css({"display":"inline"})
|
||||
$jq("input[type=hidden][name=type]").attr("value", "name/tripcode")
|
||||
break;
|
||||
}
|
||||
|
||||
$jq("select#ban-type").bind("change", function (e){
|
||||
var new_selection = this.value;
|
||||
switch(new_selection) {
|
||||
case "Single IP/IP range":
|
||||
$jq("div#ip.ban-type-div").css({"display":"inline"})
|
||||
$jq("div#name.ban-type-div").css({"display":"none"})
|
||||
$jq("input[type=hidden][name=type]").attr("value", "ip")
|
||||
break;
|
||||
case "Name/tripcode":
|
||||
$jq("div#ip.ban-type-div").css({"display":"none"})
|
||||
$jq("div#name.ban-type-div").css({"display":"inline"});
|
||||
$jq("input[type=hidden][name=type]").attr("value", "name-tripcode")
|
||||
break;
|
||||
}
|
||||
});
|
||||
$jq("input[type=checkbox]#allboards").bind("change", function() {
|
||||
var allboards_check = this;
|
||||
$jq("input[type=checkbox].board-check").each(function() {
|
||||
this.checked = allboards_check.checked;
|
||||
});
|
||||
});
|
||||
$jq("div.duration-select").html(
|
||||
"<select class=\"duration-months\">" +
|
||||
"<option>Months...</option>" +
|
||||
"</select>" +
|
||||
"<select class=\"duration-days\">" +
|
||||
"<option>Days...</option>" +
|
||||
"</select>" +
|
||||
"<select class=\"duration-hours\">" +
|
||||
"<option>Hours...</option>" +
|
||||
"</select>" +
|
||||
"<select class=\"duration-minutes\">" +
|
||||
"<option>Minutes...</option>" +
|
||||
"</select>"
|
||||
);
|
||||
var months_html = "";
|
||||
var i;
|
||||
for(i = 0; i < 49; i++) {
|
||||
months_html += "<option>" + i + "</option>";
|
||||
}
|
||||
|
||||
var days_html = "";
|
||||
for(i = 0; i < 33; i++) {
|
||||
days_html += "<option>" + i + "</option>";
|
||||
}
|
||||
|
||||
var hours_html = "";
|
||||
for(i = 0; i < 25; i++) {
|
||||
hours_html += "<option>" + i + "</option>";
|
||||
}
|
||||
|
||||
var minutes_html = "";
|
||||
for(i = 0; i < 61; i++) {
|
||||
minutes_html += "<option>" + i + "</option>";
|
||||
}
|
||||
$jq("select.duration-months").append(months_html);
|
||||
$jq("select.duration-days").append(days_html);
|
||||
$jq("select.duration-hours").append(hours_html);
|
||||
$jq("select.duration-minutes").append(minutes_html);
|
||||
/*if(watermark) {
|
||||
$jq("input[type=text][name=ip]").watermark("IP address");
|
||||
$jq("input[type=text][name=ip]").prev().remove();
|
||||
$jq($jq("div#reason-staffnote input")[0]).prev().remove();
|
||||
$jq($jq("div#reason-staffnote input")[0]).watermark("Reason");
|
||||
$jq($jq("div#reason-staffnote input")[1]).watermark("Staff note");
|
||||
$jq($jq("div#reason-staffnote input")[1]).prev().remove();
|
||||
}*/
|
||||
}
|
||||
|
||||
function getManagePage() {
|
||||
|
||||
}
|
||||
|
@ -224,10 +141,6 @@ function openStaffLightBox(action_url) {
|
|||
});
|
||||
}
|
||||
|
||||
$jq(document).ready(function() {
|
||||
/*if(location.pathname.indexOf("/manage" == location.pathname.length -7)) {
|
||||
if(getArg("action") == "banuser") {
|
||||
banPage();
|
||||
}
|
||||
}*/
|
||||
});
|
||||
/* $jq(document).ready(function() {
|
||||
|
||||
}); */
|
||||
|
|
26
src/durationparse_test.go
Normal file
26
src/durationparse_test.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDurationParse(t *testing.T) {
|
||||
duration, err := parseDurationString("7y6mo5w4d3h2m1s")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
fmt.Println(duration)
|
||||
|
||||
duration, err = parseDurationString("7year6month5weeks4days3hours2minutes1second")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
fmt.Println(duration)
|
||||
|
||||
duration, err = parseDurationString("7 years 6 months 5 weeks 4 days 3 hours 2 minutes 1 seconds")
|
||||
if err != nil {
|
||||
t.Fatal(err.Error())
|
||||
}
|
||||
fmt.Println(duration)
|
||||
}
|
|
@ -14,11 +14,9 @@ func main() {
|
|||
}
|
||||
}()
|
||||
initConfig()
|
||||
config.Version = version
|
||||
printf(0, "Starting gochan v%s.%s, using verbosity level %d\n", config.Version, buildtimeString, config.Verbosity)
|
||||
println(0, "Config file loaded. Connecting to database...")
|
||||
connectToSQLServer()
|
||||
|
||||
println(0, "Loading and parsing templates...")
|
||||
if err := initTemplates(); err != nil {
|
||||
handleError(0, customError(err))
|
||||
|
@ -26,12 +24,9 @@ func main() {
|
|||
}
|
||||
|
||||
println(0, "Initializing server...")
|
||||
if db != nil {
|
||||
_, err := db.Exec("USE `" + config.DBname + "`")
|
||||
if err != nil {
|
||||
handleError(0, customError(err))
|
||||
os.Exit(2)
|
||||
}
|
||||
if _, err := db.Exec("USE `" + config.DBname + "`"); err != nil {
|
||||
handleError(0, customError(err))
|
||||
os.Exit(2)
|
||||
}
|
||||
initServer()
|
||||
}
|
||||
|
|
121
src/manage.go
121
src/manage.go
|
@ -41,12 +41,7 @@ func callManageFunction(writer http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
|
||||
if action != "getstaffjquery" {
|
||||
if err = global_header_tmpl.Execute(&managePageBuffer, config); err != nil {
|
||||
handleError(0, customError(err))
|
||||
fmt.Fprintf(writer, mangePageHTML+err.Error()+"\n</body>\n</html>")
|
||||
return
|
||||
}
|
||||
|
||||
managePageBuffer.WriteString("<!DOCTYPE html>\n<html>\n<head>\n")
|
||||
if err = manage_header_tmpl.Execute(&managePageBuffer, config); err != nil {
|
||||
handleError(0, customError(err))
|
||||
fmt.Fprintf(writer, mangePageHTML+err.Error()+"\n</body>\n</html>")
|
||||
|
@ -574,118 +569,28 @@ var manage_functions = map[string]ManageFunction{
|
|||
"bans": {
|
||||
Permissions: 1,
|
||||
Callback: func(writer http.ResponseWriter, request *http.Request) (html string) {
|
||||
var ban_which string // user, image, or both
|
||||
|
||||
if request.PostFormValue("ban-user-button") == "Ban user" {
|
||||
ban_which = "user"
|
||||
} else if request.PostFormValue("ban-image-button") == "Ban image" {
|
||||
ban_which = "image"
|
||||
} else if request.PostFormValue("ban-both-button") == "Ban both" {
|
||||
ban_which = "both"
|
||||
}
|
||||
// if none of these are true, we can assume that the page was loaded without sending anything
|
||||
println(1, "ban_which"+ban_which)
|
||||
|
||||
if ban_which == "user" {
|
||||
//var banned_tripcode string
|
||||
banned_ip := request.PostFormValue("ip")
|
||||
if banned_ip != "" {
|
||||
println(0, banned_ip)
|
||||
}
|
||||
}
|
||||
|
||||
boards_list_html := " <span style=\"font-weight: bold;\">Boards: </span><br />\n" +
|
||||
" <label>All boards <input type=\"checkbox\" id=\"allboards\" /></label> overrides individual board selection<br />\n"
|
||||
|
||||
rows, err := querySQL("SELECT `dir` FROM `" + config.DBprefix + "boards`")
|
||||
rows, err := querySQL("SELECT `ip`,`name`,`tripcode`,`reason`,`boards`,`banned_by`,`timestamp`,`expires` FROM `" + config.DBprefix + "banlist`")
|
||||
defer closeRows(rows)
|
||||
if err != nil {
|
||||
html += "<hr />" + handleError(1, err.Error())
|
||||
return
|
||||
}
|
||||
var board_dir string
|
||||
|
||||
var banlist []BanlistTable
|
||||
for rows.Next() {
|
||||
if err = rows.Scan(&board_dir); err != nil {
|
||||
html += "<hr />" + handleError(1, err.Error())
|
||||
}
|
||||
boards_list_html += " <label>/" + board_dir + "/ <input type=\"checkbox\" id=\"" + board_dir + "\" class=\"board-check\"/></label> \n"
|
||||
var ban BanlistTable
|
||||
rows.Scan(&ban.IP, &ban.Name, &ban.Tripcode, &ban.Reason, &ban.Boards, &ban.BannedBy, &ban.Timestamp, &ban.Expires)
|
||||
banlist = append(banlist, ban)
|
||||
}
|
||||
manageBansBuffer := bytes.NewBufferString("")
|
||||
|
||||
html = "<h1>Ban user(s)</h1>\n" +
|
||||
"<form method=\"POST\" action=\"/manage\">\n" +
|
||||
"<input type=\"hidden\" name=\"action\" value=\"bans\" />\n" +
|
||||
"<fieldset><legend>User(s)</legend>" +
|
||||
" <div id=\"ip\" class=\"ban-type-div\" style=\"width:100%%; display: inline;\">\n" +
|
||||
" <span style=\"font-weight: bold;\">IP address:</span> <input type=\"text\" name=\"ip\" /><br />\n" +
|
||||
" \"192.168.1.36\" will ban posts from that IP address<br />\n" +
|
||||
" \"192.168\" will block all IPs starting with 192.168<br /><hr />\n" +
|
||||
" </div>\n" +
|
||||
" <div id=\"name\" class=\"ban-type-div\" style=\"width:100%%;\">\n" +
|
||||
" <span style=\"font-weight: bold;\">Name/tripcode:</span> <input type=\"text\" name=\"ip\" /><br />\n" +
|
||||
" (format: \"Poster!tripcode\", \"!tripcode\", or \"Poster\")<br />\n" +
|
||||
" <hr />\n" +
|
||||
" </div>\n" +
|
||||
" <span style=\"font-weight: bold;\">Duration: </span><br />\n" +
|
||||
" <label>Permanent ban (overrides duration dropdowns if checked)<input type=\"checkbox\" name=\"forever\" value=\"forever\" /></label><br />\n" +
|
||||
" <div class=\"duration-select\"></div>\n<hr />\n" +
|
||||
boards_list_html + "<hr />\n" +
|
||||
" <div id=\"reason-staffnote\" style=\"text-align: right; float:left;\">\n" +
|
||||
" <span style=\"font-weight: bold;\">Reason: </span><input type=\"text\" name=\"reason\" /><br />\n" +
|
||||
" <span style=\"font-weight: bold;\">Staff note: </span><input type=\"text\" name=\"staff-note\" /><br />\n" +
|
||||
" </div>\n<br /><br /><br /><input type=\"submit\" name=\"ban-user-button\" value=\"Ban user\"/>" +
|
||||
"</fieldset>\n<br />\n<hr />\n" +
|
||||
"<fieldset><legend>Image</legend>\n" +
|
||||
" This will disallow an image with this hash from being posted, and will ban users who try to post it for the specified amount of time.<br /><br />\n" +
|
||||
" <label style=\"font-weight: bold;\">Ban image hash: <input type=\"checkbox\" /></label><br />\n" +
|
||||
" <span style=\"font-weight: bold;\">Duration: </span><br />\n" +
|
||||
" <label>Permanent ban (overrides duration dropdowns if checked)<input type=\"checkbox\" name=\"forever\" value=\"forever\" /></label><br />\n" +
|
||||
" <div class=\"duration-select\"></div>\n" +
|
||||
" <hr />\n" +
|
||||
boards_list_html + "<hr />\n" +
|
||||
" <div id=\"reason-staffnote\" style=\"text-align: right; float:left;\">\n" +
|
||||
" <span style=\"font-weight: bold;\">Reason: </span><input type=\"text\" name=\"reason\" /><br />\n" +
|
||||
" <span style=\"font-weight: bold;\">Staff note: </span><input type=\"text\" name=\"staff-note\" /><br />\n" +
|
||||
" </div>\n<br /><br /><br /><input type=\"submit\" name=\"ban-image-button\" value=\"Ban image\"/>" +
|
||||
"</fieldset><br />\n" +
|
||||
"<input type=\"submit\" name=\"ban-both-button\" value=\"Ban both\" /></form>\n</br />" +
|
||||
"<h2>Banned IPs</h2>\n"
|
||||
|
||||
rows, err = querySQL("SELECT * FROM `" + config.DBprefix + "banlist`")
|
||||
if err != nil {
|
||||
html += "</table><br />" + handleError(1, err.Error())
|
||||
if err := manage_bans_tmpl.Execute(manageBansBuffer,
|
||||
map[string]interface{}{"config": config, "banlist": banlist, "boards": allBoards},
|
||||
); err != nil {
|
||||
html += handleError(1, err.Error())
|
||||
return
|
||||
}
|
||||
var ban BanlistTable
|
||||
|
||||
num_rows := 0
|
||||
for rows.Next() {
|
||||
if num_rows == 0 {
|
||||
html += "<table width=\"100%%\" border=\"1\">\n" +
|
||||
"<tr><th>IP</th><th>Name/Tripcode</th><th>Message</th><th>Date added</th><th>Added by</th><th>Reason</th><th>Expires/expired</th><th></th></tr>"
|
||||
}
|
||||
err = rows.Scan(&ban.ID, &ban.AllowRead, &ban.IP, &ban.Name, &ban.Tripcode, &ban.Message, &ban.SilentBan, &ban.Boards, &ban.BannedBy, &ban.Timestamp, &ban.Expires, &ban.Reason, &ban.StaffNote, &ban.AppealMessage, &ban.AppealAt)
|
||||
if err != nil {
|
||||
html += "</table><br />" + handleError(1, err.Error())
|
||||
return
|
||||
}
|
||||
ban_name := ""
|
||||
if ban.Name+ban.Tripcode != "" {
|
||||
ban_name = ban.Name + "!" + ban.Tripcode
|
||||
}
|
||||
|
||||
html += "<tr><td>" + ban.IP + "</td><td>" + ban_name + "</td><td>" + ban.Message + "</td><td>" + humanReadableTime(ban.Timestamp) + "</td><td>" + ban.BannedBy + "</td><td>" + ban.Reason + "</td><td>" + humanReadableTime(ban.Expires) + "</td><td>Delete</td></tr>"
|
||||
num_rows++
|
||||
}
|
||||
if num_rows == 0 {
|
||||
html += "No banned IPs"
|
||||
} else {
|
||||
html += "</table>\n"
|
||||
}
|
||||
|
||||
// html += "<tr><td>127.0.0.1</td><td>Banned message</td><td>12/25/1991</td><td>Luna</td><td>Spam</td><td>never</td><td>Delete</td></tr>" +
|
||||
|
||||
html += "<br /><br /><br />" +
|
||||
"<script type=\"text/javascript\">banPage();</script>\n "
|
||||
html += manageBansBuffer.String()
|
||||
return
|
||||
}},
|
||||
"getstaffjquery": {
|
||||
|
|
|
@ -35,7 +35,6 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
lastPost PostTable
|
||||
allSections []interface{}
|
||||
allBoards []interface{}
|
||||
)
|
||||
|
@ -386,7 +385,7 @@ func buildThreadPages(op *PostTable) (html string) {
|
|||
"posts": replies,
|
||||
"op": op,
|
||||
}); err != nil {
|
||||
html += handleError(1, "Failed building /%s/res/%d threadpage: ", board.Dir, op.ID, err.Error()) + "<br />\n"
|
||||
html += handleError(1, "Failed building /%s/res/%d threadpage: %s", board.Dir, op.ID, err.Error()) + "<br />\n"
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -564,38 +563,14 @@ func bumpThread(postID, boardID int) error {
|
|||
}
|
||||
|
||||
// Checks check poster's name/tripcode/file checksum (from PostTable post) for banned status
|
||||
// returns true if the user is banned
|
||||
func checkBannedStatus(post *PostTable, writer http.ResponseWriter) ([]interface{}, error) {
|
||||
// returns ban table if the user is banned or errNotBanned if they aren't
|
||||
func getBannedStatus(post *PostTable, writer http.ResponseWriter) (BanlistTable, error) {
|
||||
var banEntry BanlistTable
|
||||
var interfaces []interface{}
|
||||
// var count int
|
||||
// var search string
|
||||
err := queryRowSQL("SELECT `ip`, `name`, `tripcode`, `message`, `boards`, `timestamp`, `expires`, `appeal_at` FROM `"+config.DBprefix+"banlist` WHERE `ip` = ?",
|
||||
err := queryRowSQL("SELECT `ip`, `name`, `reason`, `boards`, `timestamp`, `expires`, `appeal_at` FROM `"+config.DBprefix+"banlist` WHERE `ip` = ? ORDER BY `id` DESC LIMIT 1",
|
||||
[]interface{}{&post.IP},
|
||||
[]interface{}{&banEntry.IP, &banEntry.Name, &banEntry.Tripcode, &banEntry.Message, &banEntry.Boards, &banEntry.Timestamp, &banEntry.Expires, &banEntry.AppealAt},
|
||||
[]interface{}{&banEntry.IP, &banEntry.Name, &banEntry.Reason, &banEntry.Boards, &banEntry.Timestamp, &banEntry.Expires, &banEntry.AppealAt},
|
||||
)
|
||||
if err == sql.ErrNoRows {
|
||||
// the user isn't banned
|
||||
// We don't need to return err because it isn't necessary
|
||||
return interfaces, nil
|
||||
} else if err != nil {
|
||||
handleError(1, "Error checking banned status: "+err.Error())
|
||||
return interfaces, err
|
||||
}
|
||||
|
||||
if !banEntry.Expires.After(time.Now()) {
|
||||
// if it is expired, send a message saying that it's expired, but still post
|
||||
println(1, "expired")
|
||||
return interfaces, nil
|
||||
}
|
||||
// the user's IP is in the banlist. Check if the ban has expired
|
||||
if getSpecificSQLDateTime(banEntry.Expires) == "0001-01-01 00:00:00" || banEntry.Expires.After(time.Now()) {
|
||||
// for some funky reason, Go's MySQL driver seems to not like getting a supposedly nil timestamp as an ACTUAL nil timestamp
|
||||
// so we're just going to wing it and cheat. Of course if they change that, we're kind of hosed.
|
||||
|
||||
return []interface{}{config, banEntry}, nil
|
||||
}
|
||||
return interfaces, nil
|
||||
return banEntry, err
|
||||
}
|
||||
|
||||
func sinceLastPost(post *PostTable) int {
|
||||
|
@ -673,7 +648,7 @@ func getVideoInfo(path string) (map[string]int, error) {
|
|||
func getNewFilename() string {
|
||||
now := time.Now().Unix()
|
||||
rand.Seed(now)
|
||||
return strconv.Itoa(int(now)) + strconv.Itoa(int(rand.Intn(98)+1))
|
||||
return strconv.Itoa(int(now)) + strconv.Itoa(rand.Intn(98)+1)
|
||||
}
|
||||
|
||||
// find out what out thumbnail's width and height should be, partially ripped from Kusaba X
|
||||
|
@ -1041,19 +1016,19 @@ func makePost(writer http.ResponseWriter, request *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
isBanned, err := checkBannedStatus(&post, writer)
|
||||
if err != nil {
|
||||
handleError(1, "Error in checkBannedStatus: "+err.Error())
|
||||
banStatus, err := getBannedStatus(&post, writer)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
handleError(1, "Error in getBannedStatus: "+err.Error())
|
||||
serveErrorPage(writer, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
if len(isBanned) > 0 {
|
||||
if banStatus.IsBanned() {
|
||||
var banpage_buffer bytes.Buffer
|
||||
var banpage_html string
|
||||
banpage_buffer.Write([]byte(""))
|
||||
if err = banpage_tmpl.Execute(&banpage_buffer, map[string]interface{}{
|
||||
"bans": isBanned,
|
||||
"config": config, "ban": banStatus,
|
||||
}); err != nil {
|
||||
fmt.Fprintf(writer, banpage_html+handleError(1, err.Error())+"\n</body>\n</html>")
|
||||
return
|
||||
|
@ -1062,7 +1037,7 @@ func makePost(writer http.ResponseWriter, request *http.Request) {
|
|||
return
|
||||
}
|
||||
|
||||
sanitizePost(&post)
|
||||
post.Sanitize()
|
||||
result, err := insertPost(post, emailCommand != "sage")
|
||||
if err != nil {
|
||||
serveErrorPage(writer, handleError(1, err.Error()))
|
||||
|
|
|
@ -231,15 +231,14 @@ var (
|
|||
banpage_tmpl *template.Template
|
||||
errorpage_tmpl *template.Template
|
||||
front_page_tmpl *template.Template
|
||||
global_header_tmpl *template.Template
|
||||
img_boardpage_tmpl *template.Template
|
||||
img_threadpage_tmpl *template.Template
|
||||
img_post_form_tmpl *template.Template
|
||||
// manage_bans_tmpl *template.Template
|
||||
manage_boards_tmpl *template.Template
|
||||
manage_config_tmpl *template.Template
|
||||
manage_header_tmpl *template.Template
|
||||
post_edit_tmpl *template.Template
|
||||
manage_bans_tmpl *template.Template
|
||||
manage_boards_tmpl *template.Template
|
||||
manage_config_tmpl *template.Template
|
||||
manage_header_tmpl *template.Template
|
||||
post_edit_tmpl *template.Template
|
||||
)
|
||||
|
||||
func loadTemplate(files ...string) (*template.Template, error) {
|
||||
|
@ -262,7 +261,7 @@ func templateError(name string, err error) error {
|
|||
func initTemplates() error {
|
||||
var err error
|
||||
resetBoardSectionArrays()
|
||||
banpage_tmpl, err = loadTemplate("banpage.html")
|
||||
banpage_tmpl, err = loadTemplate("banpage.html", "global_footer.html")
|
||||
if err != nil {
|
||||
return templateError("banpage.html", err)
|
||||
}
|
||||
|
@ -272,11 +271,6 @@ func initTemplates() error {
|
|||
return templateError("error.html", err)
|
||||
}
|
||||
|
||||
global_header_tmpl, err = loadTemplate("global_header.html")
|
||||
if err != nil {
|
||||
return templateError("global_header.html", err)
|
||||
}
|
||||
|
||||
img_boardpage_tmpl, err = loadTemplate("img_boardpage.html", "img_header.html", "postbox.html", "global_footer.html")
|
||||
if err != nil {
|
||||
return templateError("img_boardpage.html", err)
|
||||
|
@ -292,10 +286,10 @@ func initTemplates() error {
|
|||
return templateError("img_threadpage.html", err)
|
||||
}
|
||||
|
||||
/* manage_bans_tmpl, err = loadTemplate("manage_bans.html")
|
||||
manage_bans_tmpl, err = loadTemplate("manage_bans.html")
|
||||
if err != nil {
|
||||
return templateError("manage_bans.html", err)
|
||||
} */
|
||||
}
|
||||
|
||||
manage_boards_tmpl, err = loadTemplate("manage_boards.html")
|
||||
if err != nil {
|
||||
|
|
30
src/types.go
30
src/types.go
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"html"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
|
@ -73,6 +74,13 @@ type BanlistTable struct {
|
|||
AppealAt time.Time
|
||||
}
|
||||
|
||||
func (bt *BanlistTable) IsBanned() bool {
|
||||
if getSpecificSQLDateTime(bt.Expires) == "0001-01-01 00:00:00" || bt.Expires.After(time.Now()) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type BannedHashesTable struct {
|
||||
ID uint
|
||||
Checksum string
|
||||
|
@ -134,17 +142,6 @@ type EmbedsTable struct {
|
|||
EmbedCode string
|
||||
}
|
||||
|
||||
// FiletypesTable represents the allowed filetypes
|
||||
// It's held over from Kusaba X and may be removed in the future
|
||||
type FiletypesTable struct {
|
||||
ID uint8
|
||||
Filetype string
|
||||
Mime string
|
||||
ThumbImage string
|
||||
ImageW uint
|
||||
ImageH uint
|
||||
}
|
||||
|
||||
// FrontTable represents the information (News, rules, etc) on the front page
|
||||
type FrontTable struct {
|
||||
ID int
|
||||
|
@ -157,7 +154,7 @@ type FrontTable struct {
|
|||
Email string
|
||||
}
|
||||
|
||||
// FrontLinksTable is used for linking to sites that the admin linkes
|
||||
// FrontLinksTable is used for linking to sites that the admin likes
|
||||
type FrontLinksTable struct {
|
||||
ID uint8
|
||||
Title string
|
||||
|
@ -221,6 +218,15 @@ type PostTable struct {
|
|||
Sillytag bool
|
||||
}
|
||||
|
||||
// Sanitize escapes HTML strings in a post. This should be run immediately before
|
||||
// the post is inserted into the database
|
||||
func (p *PostTable) Sanitize() {
|
||||
p.Name = html.EscapeString(p.Name)
|
||||
p.Email = html.EscapeString(p.Email)
|
||||
p.Subject = html.EscapeString(p.Subject)
|
||||
p.Password = html.EscapeString(p.Password)
|
||||
}
|
||||
|
||||
type ReportsTable struct {
|
||||
ID uint
|
||||
Board string
|
||||
|
|
61
src/util.go
61
src/util.go
|
@ -5,8 +5,8 @@ import (
|
|||
"crypto/md5"
|
||||
"crypto/sha1"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"fmt"
|
||||
"html"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
|
@ -16,6 +16,7 @@ import (
|
|||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -24,7 +25,10 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
nullTime, _ = time.Parse("2006-01-02 15:04:05", "0000-00-00 00:00:00")
|
||||
nullTime, _ = time.Parse("2006-01-02 15:04:05", "0000-00-00 00:00:00")
|
||||
errEmptyDurationString = errors.New("Empty Duration string")
|
||||
errInvalidDurationString = errors.New("Invalid Duration string")
|
||||
durationRegexp = regexp.MustCompile(`^((\d+)\s?ye?a?r?s?)?\s?((\d+)\s?mon?t?h?s?)?\s?((\d+)\s?we?e?k?s?)?\s?((\d+)\s?da?y?s?)?\s?((\d+)\s?ho?u?r?s?)?\s?((\d+)\s?mi?n?u?t?e?s?)?\s?((\d+)\s?s?e?c?o?n?d?s?)?$`)
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -410,7 +414,6 @@ func paginate(interfaceLength int, interf []interface{}) [][]interface{} {
|
|||
var paginatedInterfaces [][]interface{}
|
||||
numArrays := len(interf) / interfaceLength
|
||||
interfacesRemaining := len(interf) % interfaceLength
|
||||
//paginated_interfaces = append(paginated_interfaces, interf)
|
||||
currentInterface := 0
|
||||
for l := 0; l < numArrays; l++ {
|
||||
paginatedInterfaces = append(paginatedInterfaces,
|
||||
|
@ -449,15 +452,6 @@ func resetBoardSectionArrays() {
|
|||
allSections = append(allSections, allSectionsArr...)
|
||||
}
|
||||
|
||||
// sanitize/escape HTML strings in a post. This should be run immediately before
|
||||
// the post is inserted into the database
|
||||
func sanitizePost(post *PostTable) {
|
||||
post.Name = html.EscapeString(post.Name)
|
||||
post.Email = html.EscapeString(post.Email)
|
||||
post.Subject = html.EscapeString(post.Subject)
|
||||
post.Password = html.EscapeString(post.Password)
|
||||
}
|
||||
|
||||
func searchStrings(item string, arr []string, permissive bool) int {
|
||||
for i, str := range arr {
|
||||
if item == str {
|
||||
|
@ -621,3 +615,46 @@ func ipMatch(newIP, existingIP string) bool {
|
|||
}
|
||||
return ipRegex.MatchString(newIP)
|
||||
}
|
||||
|
||||
// based on TinyBoard's parse_time function
|
||||
func parseDurationString(str string) (time.Duration, error) {
|
||||
if str == "" {
|
||||
return 0, errEmptyDurationString
|
||||
}
|
||||
|
||||
matches := durationRegexp.FindAllStringSubmatch(str, -1)
|
||||
if len(matches) == 0 {
|
||||
return 0, errInvalidDurationString
|
||||
}
|
||||
|
||||
var expire int
|
||||
if matches[0][2] != "" {
|
||||
years, _ := strconv.Atoi(matches[0][2])
|
||||
expire += years * 60 * 60 * 24 * 365
|
||||
}
|
||||
if matches[0][4] != "" {
|
||||
months, _ := strconv.Atoi(matches[0][4])
|
||||
expire += months * 60 * 60 * 24 * 30
|
||||
}
|
||||
if matches[0][6] != "" {
|
||||
weeks, _ := strconv.Atoi(matches[0][6])
|
||||
expire += weeks * 60 * 60 * 24 * 7
|
||||
}
|
||||
if matches[0][8] != "" {
|
||||
days, _ := strconv.Atoi(matches[0][8])
|
||||
expire += days * 60 * 60 * 24
|
||||
}
|
||||
if matches[0][10] != "" {
|
||||
hours, _ := strconv.Atoi(matches[0][10])
|
||||
expire += hours * 60 * 60
|
||||
}
|
||||
if matches[0][12] != "" {
|
||||
minutes, _ := strconv.Atoi(matches[0][12])
|
||||
expire += minutes * 60
|
||||
}
|
||||
if matches[0][14] != "" {
|
||||
seconds, _ := strconv.Atoi(matches[0][14])
|
||||
expire += seconds
|
||||
}
|
||||
return time.ParseDuration(strconv.Itoa(expire) + "s")
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>Banned</title>
|
||||
<link rel="shortcut icon" href="/favicon.png">
|
||||
<link rel="stylesheet" href="/css/global/front.css" />
|
||||
{{range $i, $style := .config.Styles}}
|
||||
<link rel="{{if not (isStyleDefault $style)}}alternate {{end}}stylesheet" href="/css/{{$style}}/front.css" />{{end}}
|
||||
|
@ -18,40 +19,33 @@
|
|||
<span id="site-title">{{.config.SiteName}}</span><br />
|
||||
<span id="site-slogan">{{.config.SiteSlogan}}</span>
|
||||
</div>
|
||||
<br />
|
||||
<br />
|
||||
<br /><br />
|
||||
<div class="section-block" style="margin: 0px 26px 0px 24px">
|
||||
<div class="section-title-block">
|
||||
<span class="section-title"><b>YOU ARE BANNED :(</b></span>
|
||||
</div>
|
||||
<div class="section-body" style="padding-top:8px">
|
||||
<div id="ban-info" style="float:left">
|
||||
{{if eq .ban.Boards "*"}}
|
||||
You are banned from posting on <b>all boards</b> for the following reason:
|
||||
{{else}}
|
||||
You are banned from posting on <b>{{.ban.Boards}}</b> for the following reason:
|
||||
{{end}}
|
||||
<div id="ban-info" style="float:left">{{if eq $.ban.Boards ""}}
|
||||
You are banned from posting on <b>all boards</b> for the following reason:{{else}}
|
||||
You are banned from posting on <b>{{.ban.Boards}}</b> for the following reason:{{end}}
|
||||
<br /><br />
|
||||
<b>{{.ban.Message}}</b>
|
||||
<b>{{.ban.Reason}}</b>
|
||||
<br /><br />{{$expires_timestamp := formatTimestamp .ban.Expires}}{{$appeal_timestamp := formatTimestamp .ban.AppealAt}}{{if eq $expires_timestamp "Mon, January 01, 0001 00:00 AM"}}
|
||||
Your ban was placed on {{formatTimestamp .ban.Timestamp}} and will <b>not expire.</b><br />{{else}}
|
||||
Your ban was placed on <b>{{formatTimestamp .ban.Timestamp}}</b> and will expire on <b>{{$expires_timestamp}}</b><br />{{end}}
|
||||
<br />{{if eq $appeal_timestamp "Mon, January 01, 0001 00:00 AM"}}
|
||||
You may not appeal this ban.{{else}}
|
||||
You may appeal this ban on <b>{{$appeal_timestamp}}</b>.{{end}}
|
||||
<br /><br />
|
||||
{{$expires_timestamp := formatTimestamp .ban.Expires}}
|
||||
{{$appeal_timestamp := formatTimestamp .ban.AppealAt}}
|
||||
{{if eq $expires_timestamp "Mon, January 01, 0001 00:00 AM"}}
|
||||
Your ban was placed on {{formatTimestamp .ban.Timestamp}} and will not expire.<br />
|
||||
{{else}}
|
||||
Your ban was placed on {{formatTimestamp .ban.Timestamp}} and will expire on {{$expires_timestamp}}<br />
|
||||
{{end}}
|
||||
<br />
|
||||
{{if eq .appeal_timestamp "Mon, January 01, 0001 00:00 AM"}}
|
||||
You may not appeal this ban.
|
||||
{{else}}
|
||||
You may appeal this ban {{$appeal_timestamp}}
|
||||
{{end}}
|
||||
<br /><br />
|
||||
Your IP address is {{.ban.IP}}.
|
||||
Your IP address is <b>{{.ban.IP}}</b>.<br /><br />
|
||||
<form id="appeal-form">
|
||||
<table id="postbox-static">
|
||||
<tr><th class="postblock">Email</th><td><input type="email" name="email" /><input type="submit" value="Appeal" /></td></tr>
|
||||
<tr><th class="postblock">Message</th><td><textarea rows="4" cols="48" name="postmsg" id="postmsg"></textarea></td></tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<img id="banpage-image" src="/banned.jpg" style="float:right; margin: 4px 8px 8px 4px"/>
|
||||
<img id="banpage-image" src="/banned.jpg" style="float:right; margin: 4px 8px 8px 4px"/><br />
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{{template "global_footer.html" .}}
|
|
@ -1,3 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
33
templates/manage_bans.html
Normal file
33
templates/manage_bans.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
<h1>Ban user</h1>
|
||||
<form method="POST" action="/manage">
|
||||
<input type="hidden" name="action" value="bans" />
|
||||
|
||||
<fieldset><legend>User filter</legend>
|
||||
<b>IP address:</b> <input type="text" name="ip" /><br />
|
||||
"192.168.1.36" will ban posts from that IP address<br />
|
||||
"192.168" will block all IPs starting with 192.168<br /><hr />
|
||||
<b>Name!Tripcode:</b> <input type="text" name="name" /><br />
|
||||
<b>Ban filename:</b> <input type="text" name="filename" /><br />
|
||||
<b>Ban file checksum: </b> <i>3bdffa672fefe458223629815d3b63e1</i> <input type="checkbox" />
|
||||
</fieldset><br />
|
||||
|
||||
<fieldset><legend>Ban info</legend>
|
||||
<b>Duration:</b><sup title="e.g. '1y2mo3w4d5h6m7s', '1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds' or 'forever', '0', or '' for a permaban">[?]</sup> <input type="text" name="ban-duration" /><br />
|
||||
<b>Ban type:</b><br />
|
||||
<label>Image ban <input type="checkbox" name="image-ban" /></label><br />
|
||||
<label>Thread starting ban <input type="checkbox" name="thread-ban" /></label><br />
|
||||
<label>Full ban (overrides the above) <input type="checkbox" name="full-ban" /></label><hr />
|
||||
<table class="baninfotable">
|
||||
<tr><td><b>Boards:</b><sup title="Comma-separated list of boards (e.g. board1,board2,board3) or blank for all boards">[?]</sup></td><td><input type="text" name="boards" /></td></tr>
|
||||
<tr><td><b>Reason:</b></td><td><textarea name="reason" rows="5" cols="30"></textarea></td></tr>
|
||||
<tr><td><b>Staff note:</b></td><td><input type="text" name="staff-note" /></td></tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
<h2>Banlist</h2>
|
||||
<table>
|
||||
<th>IP</th><th>Name!Tripcode</th><th>Reason</th><th>Boards</th><th>Staff</th><th>Set</th><th>Expires</th>
|
||||
{{range $b, $ban := $.banlist}}<tr>
|
||||
<td>{{$ban.IP}}</td><td>{{$ban.Name}}</td><td>{{$ban.Reason}}</td><td>{{$ban.Boards}}</td><td>{{$ban.BannedBy}}</td><td>{{$ban.Timestamp}}</td><td>{{$ban.Expires}}</td>
|
||||
</tr>{{end}}
|
||||
</table>
|
|
@ -1,5 +1,8 @@
|
|||
#!/bin/bash
|
||||
# Vagrant provision script, kinda sorta based on Ponychan's
|
||||
# Vagrant provision script
|
||||
# I guess I should give credit where credit is due since a fair amount
|
||||
# of this script was was originally written by Macil (as far as I know) for Ponychan
|
||||
# https://github.com/MacilPrime/ponychan
|
||||
|
||||
set -euo pipefail
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
@ -78,6 +81,20 @@ export GOPATH=/vagrant/lib
|
|||
export GOCHAN_PATH=/home/vagrant/gochan
|
||||
EOF
|
||||
|
||||
# a couple convenience shell scripts, since they're nice to have
|
||||
cat - <<EOF >>/home/vagrant/dbconnect.sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
mysql -s -t -u gochan -D gochan -pgochan
|
||||
EOF
|
||||
chmod +x /home/vagrant/dbconnect.sh
|
||||
|
||||
cat - <<EOF >>/home/vagrant/buildgochan.sh
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cd /vagrant && make debug && cd ~/gochan && ./gochan
|
||||
EOF
|
||||
|
||||
go get github.com/disintegration/imaging
|
||||
go get github.com/nranchev/go-libGeoIP
|
||||
go get github.com/nyarla/go-crypt
|
||||
|
|
2
version
2
version
|
@ -1 +1 @@
|
|||
1.11.0
|
||||
1.12.0
|
Loading…
Add table
Add a link
Reference in a new issue