Merge branch 'master' of ssh://github.com/majestrate/nntpchan
This commit is contained in:
commit
1e69493eef
@ -5,18 +5,45 @@
|
|||||||
package srnd
|
package srnd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/majestrate/configparser"
|
"github.com/majestrate/configparser"
|
||||||
"github.com/majestrate/nacl"
|
"github.com/majestrate/nacl"
|
||||||
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type FilterConfig struct {
|
||||||
|
globalFilters []*regexp.Regexp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fc *FilterConfig) LoadFile(fname string) (err error) {
|
||||||
|
var data []byte
|
||||||
|
data, err = ioutil.ReadFile(fname)
|
||||||
|
if err == nil {
|
||||||
|
r := bytes.NewReader(data)
|
||||||
|
sc := bufio.NewScanner(r)
|
||||||
|
for sc.Scan() {
|
||||||
|
txt := sc.Text()
|
||||||
|
idx := strings.Index(txt, "#")
|
||||||
|
if idx >= 0 {
|
||||||
|
txt = txt[:idx]
|
||||||
|
}
|
||||||
|
fc.globalFilters = append(fc.globalFilters, regexp.MustCompile(txt))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
type FeedConfig struct {
|
type FeedConfig struct {
|
||||||
policy FeedPolicy
|
policy FeedPolicy
|
||||||
quarks map[string]string
|
quarks map[string]string
|
||||||
@ -70,6 +97,7 @@ type SRNdConfig struct {
|
|||||||
pprof *ProfilingConfig
|
pprof *ProfilingConfig
|
||||||
hooks []*HookConfig
|
hooks []*HookConfig
|
||||||
inboundPolicy *FeedPolicy
|
inboundPolicy *FeedPolicy
|
||||||
|
filter FilterConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for config files
|
// check for config files
|
||||||
@ -417,6 +445,15 @@ func ReadConfig() *SRNdConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
filterFile := "filters.txt"
|
||||||
|
|
||||||
|
if CheckFile(filterFile) {
|
||||||
|
err = sconf.filter.LoadFile(filterFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to load %s: %s", filterFile, err)
|
||||||
|
}
|
||||||
|
log.Printf("loaded %d filters", len(sconf.filter.globalFilters))
|
||||||
|
}
|
||||||
return &sconf
|
return &sconf
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -131,6 +131,16 @@ type NNTPDaemon struct {
|
|||||||
article_lifetime time.Duration
|
article_lifetime time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// return true if text passes all checks and is okay for posting
|
||||||
|
func (self *NNTPDaemon) CheckText(text string) bool {
|
||||||
|
for _, re := range self.conf.filter.globalFilters {
|
||||||
|
if re.MatchString(text) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func (self NNTPDaemon) End() {
|
func (self NNTPDaemon) End() {
|
||||||
if self.listener != nil {
|
if self.listener != nil {
|
||||||
self.listener.Close()
|
self.listener.Close()
|
||||||
@ -478,6 +488,12 @@ func (self *NNTPDaemon) syncPull(proxy_type, proxy_addr, remote_addr string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *NNTPDaemon) ExpireAll() {
|
||||||
|
log.Println("expiring all orphans")
|
||||||
|
self.expire = createExpirationCore(self.database, self.store, self.informHooks)
|
||||||
|
self.expire.ExpireOrphans()
|
||||||
|
}
|
||||||
|
|
||||||
// run daemon
|
// run daemon
|
||||||
func (self *NNTPDaemon) Run() {
|
func (self *NNTPDaemon) Run() {
|
||||||
|
|
||||||
|
@ -77,6 +77,7 @@ func (self expire) ExpireThread(group, rootMsgid string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.database.DeleteThread(rootMsgid)
|
self.database.DeleteThread(rootMsgid)
|
||||||
|
self.database.DeleteArticle(rootMsgid)
|
||||||
self.expireCache(group, rootMsgid, rootMsgid)
|
self.expireCache(group, rootMsgid, rootMsgid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -393,7 +393,7 @@ func (self *httpFrontend) poll() {
|
|||||||
R: msg.Body,
|
R: msg.Body,
|
||||||
N: self.daemon.messageSizeLimitFor(nntp.Newsgroup()),
|
N: self.daemon.messageSizeLimitFor(nntp.Newsgroup()),
|
||||||
}
|
}
|
||||||
err = self.daemon.store.ProcessMessageBody(f, textproto.MIMEHeader(msg.Header), body)
|
err = self.daemon.store.ProcessMessageBody(f, textproto.MIMEHeader(msg.Header), body, self.daemon.CheckText)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -803,6 +803,11 @@ func (self *httpFrontend) handle_postRequest(pr *postRequest, b bannedFunc, e er
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !self.daemon.CheckText(pr.Message) {
|
||||||
|
e(errors.New("spam"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if len(pr.Frontend) == 0 {
|
if len(pr.Frontend) == 0 {
|
||||||
// :-DDD
|
// :-DDD
|
||||||
pr.Frontend = "mongo.db.is.web.scale"
|
pr.Frontend = "mongo.db.is.web.scale"
|
||||||
|
@ -565,7 +565,7 @@ func (self *nntpConnection) storeMessage(daemon *NNTPDaemon, hdr textproto.MIMEH
|
|||||||
// now store attachments and article
|
// now store attachments and article
|
||||||
err = writeMIMEHeader(f, hdr)
|
err = writeMIMEHeader(f, hdr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
err = daemon.store.ProcessMessageBody(f, hdr, body)
|
err = daemon.store.ProcessMessageBody(f, hdr, body, daemon.CheckText)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
// tell daemon
|
// tell daemon
|
||||||
daemon.loadFromInfeed(msgid)
|
daemon.loadFromInfeed(msgid)
|
||||||
|
@ -65,7 +65,7 @@ type ArticleStore interface {
|
|||||||
// process body of nntp message, register attachments and the article
|
// process body of nntp message, register attachments and the article
|
||||||
// write the body into writer as we go through the body
|
// write the body into writer as we go through the body
|
||||||
// does NOT write mime header
|
// does NOT write mime header
|
||||||
ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader) error
|
ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader, spamfilter func(string) bool) error
|
||||||
// register this post with the daemon
|
// register this post with the daemon
|
||||||
RegisterPost(nntp NNTPMessage) error
|
RegisterPost(nntp NNTPMessage) error
|
||||||
// register signed message
|
// register signed message
|
||||||
@ -428,8 +428,10 @@ func (self *articleStore) getMIMEHeader(messageID string) (hdr textproto.MIMEHea
|
|||||||
var msg *mail.Message
|
var msg *mail.Message
|
||||||
msg, err = readMIMEHeader(r)
|
msg, err = readMIMEHeader(r)
|
||||||
f.Close()
|
f.Close()
|
||||||
|
if msg != nil {
|
||||||
hdr = textproto.MIMEHeader(msg.Header)
|
hdr = textproto.MIMEHeader(msg.Header)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("failed to load article headers for", messageID, err)
|
log.Println("failed to load article headers for", messageID, err)
|
||||||
}
|
}
|
||||||
@ -437,8 +439,12 @@ func (self *articleStore) getMIMEHeader(messageID string) (hdr textproto.MIMEHea
|
|||||||
return hdr
|
return hdr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *articleStore) ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader) (err error) {
|
func (self *articleStore) ProcessMessageBody(wr io.Writer, hdr textproto.MIMEHeader, body *io.LimitedReader, spamfilter func(string) bool) (err error) {
|
||||||
err = read_message_body(body, hdr, self, wr, false, func(nntp NNTPMessage) {
|
err = read_message_body(body, hdr, self, wr, false, func(nntp NNTPMessage) {
|
||||||
|
if !spamfilter(nntp.Message()) {
|
||||||
|
err = errors.New("spam message")
|
||||||
|
return
|
||||||
|
}
|
||||||
err = self.RegisterPost(nntp)
|
err = self.RegisterPost(nntp)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
pk := hdr.Get("X-PubKey-Ed25519")
|
pk := hdr.Get("X-PubKey-Ed25519")
|
||||||
|
@ -66,6 +66,8 @@ func (self *VarnishCache) invalidateUkko() {
|
|||||||
self.invalidate(fmt.Sprintf("%s%so/", self.varnish_url, self.prefix))
|
self.invalidate(fmt.Sprintf("%s%so/", self.varnish_url, self.prefix))
|
||||||
// TODO: this is lazy af
|
// TODO: this is lazy af
|
||||||
self.RegenFrontPage()
|
self.RegenFrontPage()
|
||||||
|
// TODO: this is also lazy af
|
||||||
|
self.invalidate(fmt.Sprintf("%s%shistory.html", self.varnish_url, self.prefix))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *VarnishCache) pollRegen() {
|
func (self *VarnishCache) pollRegen() {
|
||||||
|
@ -94,6 +94,9 @@ func main() {
|
|||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(os.Stdout, "usage: %s tool mod [[add|del] pubkey]|[do modactiongoeshere]\n", os.Args[0])
|
fmt.Fprintf(os.Stdout, "usage: %s tool mod [[add|del] pubkey]|[do modactiongoeshere]\n", os.Args[0])
|
||||||
}
|
}
|
||||||
|
} else if tool == "expire" {
|
||||||
|
daemon.Setup()
|
||||||
|
daemon.ExpireAll()
|
||||||
} else if tool == "rethumb" {
|
} else if tool == "rethumb" {
|
||||||
if len(os.Args) >= 4 {
|
if len(os.Args) >= 4 {
|
||||||
threads := runtime.NumCPU()
|
threads := runtime.NumCPU()
|
||||||
|
@ -8,7 +8,8 @@ template parameters:
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"></meta>
|
<meta charset="utf-8"></meta>
|
||||||
<link rel="stylesheet" href="{{prefix}}static/site.css" />
|
<!-- <link rel="stylesheet" href="{{prefix}}static/site.css" /> -->
|
||||||
|
<link rel="stylesheet" href="{{prefix}}static/krane.css" />
|
||||||
<link rel="stylesheet" href="{{prefix}}static/user.css" />
|
<link rel="stylesheet" href="{{prefix}}static/user.css" />
|
||||||
<title>{{#i18n.Translations}}{{post_history_title}}{{/i18n.Translations}}</title>
|
<title>{{#i18n.Translations}}{{post_history_title}}{{/i18n.Translations}}</title>
|
||||||
</head>
|
</head>
|
||||||
|
Reference in New Issue
Block a user