1
0
Fork 0
mirror of https://github.com/Eggbertx/gochan.git synced 2025-08-28 08:06:24 -07:00

Add basic geoip detection to posts, add image to post flag template

This commit is contained in:
Eggbertx 2024-01-20 22:41:40 -08:00
parent 04d25a211f
commit 2007b90556
8 changed files with 86 additions and 14 deletions

View file

@ -345,8 +345,8 @@ func (p *Post) Insert(bumpThread bool, boardID int, locked bool, stickied bool,
}
insertSQL := `INSERT INTO DBPREFIXposts
(thread_id, is_top_post, ip, created_on, name, tripcode, is_role_signature, email, subject,
message, message_raw, password)
VALUES(?,?,PARAM_ATON,CURRENT_TIMESTAMP,?,?,?,?,?,?,?,?)`
message, message_raw, password, flag, country)
VALUES(?,?,PARAM_ATON,CURRENT_TIMESTAMP,?,?,?,?,?,?,?,?,?,?)`
bumpSQL := `UPDATE DBPREFIXthreads SET last_bump = CURRENT_TIMESTAMP WHERE id = ?`
tx, err := BeginTx()
@ -381,7 +381,7 @@ func (p *Post) Insert(bumpThread bool, boardID int, locked bool, stickied bool,
}
if _, err = stmt.Exec(
p.ThreadID, p.IsTopPost, p.IP, p.Name, p.Tripcode, p.IsRoleSignature, p.Email, p.Subject,
p.Message, p.MessageRaw, p.Password,
p.Message, p.MessageRaw, p.Password, p.Flag, p.Country,
); err != nil {
return err
}

View file

@ -1,5 +1,14 @@
package geoip
import (
"errors"
"strings"
)
var (
ErrInvalidCountry = errors.New("unrecognized country abbreviation")
)
var abbrMap = map[string]string{
"af": "Afghanistan",
"ax": "Aland Islands",
@ -247,3 +256,11 @@ var abbrMap = map[string]string{
"zm": "Zambia",
"zw": "Zimbabwe",
}
func GetCountryName(abbr string) (string, error) {
title, ok := abbrMap[strings.ToLower(abbr)]
if !ok {
return "", ErrInvalidCountry
}
return title, nil
}

View file

@ -4,6 +4,9 @@ import (
"errors"
"fmt"
"net/http"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/rs/zerolog"
)
var (
@ -15,13 +18,21 @@ var (
ErrUnrecognized = errors.New("unrecognized GeoIP handler ID")
)
// Country represents the GeoIP data used by gochan (the country/flag name and
// country abbreviation/flag filename, accessible in /static/flags/{flag}).
type Country struct {
Name string
Flag string
}
func (c *Country) IsGeoIP() bool {
if _, ok := abbrMap[c.Flag]; ok {
// IsGeoIP is true of the country has a recognized abbreviation set as its
// flag. Otherwise it is assumed to be either a custom flag, or no flag if
// the string is blank
func (c Country) IsGeoIP() bool {
if c.Flag == "" || c.Name == "" {
return false
}
if _, err := GetCountryName(c.Flag); err == nil {
return true
}
return false
@ -29,7 +40,7 @@ func (c *Country) IsGeoIP() bool {
type GeoIPHandler interface {
Init(options map[string]any) error
GetCountry(request *http.Request, board string) (*Country, error)
GetCountry(request *http.Request, board string, errEv *zerolog.Event) (*Country, error)
Close() error
}
@ -60,11 +71,21 @@ func SetupGeoIP(id string, options map[string]any) (err error) {
return activeHandler.Init(options)
}
func LookupCountry(request *http.Request, board string) (*Country, error) {
// GetCountry looks up the country the request comes from using the active handler.
// It throws ErrNotConfigured if one has not been configured
func GetCountry(request *http.Request, board string, errEv ...*zerolog.Event) (*Country, error) {
if activeHandler == nil {
return nil, ErrNotConfigured
}
return activeHandler.GetCountry(request, board)
var ev *zerolog.Event
if errEv != nil {
ev = errEv[0]
} else {
ev = gcutil.LogError(nil).
Str("ip", gcutil.GetRealIP(request))
defer ev.Discard()
}
return activeHandler.GetCountry(request, board, ev)
}
func Close() error {

View file

@ -9,6 +9,7 @@ import (
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/oschwald/maxminddb-golang"
"github.com/rs/zerolog"
)
var (
@ -87,18 +88,23 @@ func (mh *mmdbHandler) Init(options map[string]any) error {
return nil
}
func (mh *mmdbHandler) GetCountry(request *http.Request, board string) (*Country, error) {
var err error
func (mh *mmdbHandler) GetCountry(request *http.Request, board string, errEv *zerolog.Event) (*Country, error) {
if mh.db == nil {
return nil, err
return nil, nil
}
errEv.Str("board", board)
ip := net.ParseIP(gcutil.GetRealIP(request))
if ip == nil {
// this shouldn't happen unless something has gone very wrong
errEv.Err(ErrInvalidIP).Caller().Caller(1).Send()
return nil, ErrInvalidIP
}
var record mmdbRecord
err = mh.db.Lookup(ip, &record)
err := mh.db.Lookup(ip, &record)
if err != nil {
// thrown if something went wrong trying to unmarshal the database data, not
// if the country couldn't be found from the IP
errEv.Err(err).Caller().Caller(1).Send()
return nil, err
}
@ -106,8 +112,16 @@ func (mh *mmdbHandler) GetCountry(request *http.Request, board string) (*Country
Flag: record.Country.ISOCode,
}
var ok bool
if record.Country.Names == nil {
// Country not found (possibly private IP)
country.Flag = "unknown.png"
country.Name = "Unknown Country"
return country, nil
}
country.Name, ok = record.Country.Names[mh.isoCode]
if !ok {
errEv.Err(ErrInvalidISOCode).Caller().Caller(1).
Str("isoCode", mh.isoCode).Send()
return nil, ErrInvalidISOCode
}

View file

@ -18,6 +18,7 @@ import (
"github.com/gochan-org/gochan/pkg/events"
"github.com/gochan-org/gochan/pkg/gcsql"
"github.com/gochan-org/gochan/pkg/gcutil"
"github.com/gochan-org/gochan/pkg/posting/geoip"
"github.com/gochan-org/gochan/pkg/posting/uploads"
"github.com/gochan-org/gochan/pkg/server"
"github.com/gochan-org/gochan/pkg/server/serverutil"
@ -247,6 +248,17 @@ func MakePost(writer http.ResponseWriter, request *http.Request) {
return
}
if boardConfig.EnableGeoIP {
geoipInfo, err := geoip.GetCountry(request, postBoard.Dir, errEv)
if err != nil {
// GetCountry logs the error
server.ServeError(writer, "Unable to get post info", wantsJSON, nil)
return
}
post.Country = geoipInfo.Name
post.Flag = strings.ToLower(geoipInfo.Flag)
}
captchaSuccess, err := submitCaptchaResponse(request)
if err != nil {
server.ServeError(writer, "Error submitting captcha response:"+err.Error(), wantsJSON, nil)

View file

@ -19,6 +19,9 @@
<link id="theme" rel="stylesheet" href="{{webPath "/css/" .boardConfig.DefaultStyle}}" />
{{- end}}
<link rel="shortcut icon" href="{{webPath "/favicon.png"}}">
{{- if .boardConfig.EnableGeoIP -}}
<link id="flags" rel="stylesheet" href="{{webPath `/css/flags.css`}}"/>
{{- end -}}
<script type="text/javascript" src="{{webPath "/js/consts.js"}}"></script>
<script type="text/javascript" src="{{webPath "/js/gochan.js"}}"></script>
</head>

View file

@ -14,7 +14,7 @@
{{- end -}}
{{- if ne .post.Email ""}}</a>{{end}}</span>
{{- if ne .post.Tripcode ""}}<span class="tripcode">!{{.post.Tripcode}}</span>{{end -}}
{{- if ne .post.Country.Flag ""}}{{template "post_flag" .post}}{{end}} {{formatTimestamp .post.Timestamp -}}
{{- if ne .post.Country.Flag ""}}{{template "post_flag" .post.Country}}{{end}} {{formatTimestamp .post.Timestamp -}}
</label> <a href="{{.post.WebPath}}">No.</a> <a href="javascript:quote({{.post.ID}})" class="backlink-click">{{.post.ID}}</a>
<span class="status-icons">
{{- if $.thread.Locked -}}<img src="{{webPath "/static/lock.png"}}" class="locked-icon" alt="Thread locked" title="Thread locked">{{end -}}

View file

@ -1,3 +1,8 @@
{{define "post_flag"}}
<div class="flag-geoip flag-{{.Flag}}"></div>
<img {{if .IsGeoIP -}}
class="flag-geoip flag-{{.Flag}}"
{{- else -}}
class="flag-geoip" src="{{webPath `/static/flags/` .Flag}}"
{{- end -}}
title="{{.Name}}" />
{{- end -}}