402 lines
11 KiB
JavaScript
402 lines
11 KiB
JavaScript
const fs = require("fs")
|
|
const express = require("express")
|
|
const fetch = require("node-fetch")
|
|
const geoip = require("geoip-ultralight")
|
|
const JSONdb = require("simple-json-db")
|
|
var conf = require("./config")
|
|
const filestuff = require("./filestuff")
|
|
var con = require("./console")
|
|
var posts = require("./posts")
|
|
var comments = require("./comments")
|
|
const scheduler = require("./scheduler")
|
|
const log = require("./logging")
|
|
var admin = require("./admin")
|
|
// init logging
|
|
log.init( conf.logging, conf.logfile )
|
|
|
|
|
|
// general TODO:
|
|
// config! ./config.js for some configuration in js just some form stuff
|
|
// posts.rank timer config'n stuff
|
|
const app = express()
|
|
const port = 5500
|
|
|
|
// express static stuff sites:
|
|
app.get("/", (req, res) => filestuff.readFS(req, res, "html/index.html", "text/html"))
|
|
app.use("/static", express.static("html"))
|
|
|
|
// config stuff:
|
|
app.get("/config.js", (req, res) => {
|
|
let c = {
|
|
"ipget_endpoint_set": conf.ipget_endpoint_set,
|
|
"site_name": conf.site_name,
|
|
"search_enable": conf.search_enable,
|
|
"index_post_sort": conf.index_post_sort,
|
|
"commenting_enabled": conf.commenting_enabled
|
|
}
|
|
res.type("application/javascript")
|
|
res.end(`conf = ${ JSON.stringify( c ) }\n/* This file is automatically generated from config.yaml */\n`)
|
|
})
|
|
|
|
log.log("Dumping config:", log.d.datahorder)
|
|
log.log(JSON.stringify(conf), log.d.datahorder)
|
|
|
|
// meta-console commands:
|
|
con.registercmd( "stop", () => shutdown() )
|
|
con.registercmd( "exit", () => shutdown() )
|
|
con.registercmd( "appeval", (arg) => {try {console.log(eval(arg.join(" ")))} catch {console.log("Couldn't execute!")}})
|
|
|
|
// comment command
|
|
con.registercmd( "comment", (arg => {
|
|
let t
|
|
let body
|
|
sw:
|
|
switch (arg[0]) {
|
|
case "get":
|
|
if (!arg[1]) return console.log("Nothing to get!")
|
|
if (!arg[2]) { console.log("No commentID, dumping all")
|
|
let len = commentDB.get( arg[1] + "-len" )
|
|
let ret = []
|
|
for (let i = 0 ; i < len ; i++ ) {
|
|
ret.push( commentDB.get( arg[1] + "-" + i ) )
|
|
}
|
|
return console.log(ret)
|
|
} else {
|
|
console.log( commentDB.get( arg[1] + "-" + arg[2] ) )
|
|
}
|
|
break
|
|
|
|
case "push":
|
|
if (!arg[1] || !arg[2] || !arg[3] || !arg[4]) {
|
|
return console.log("Not all args specified!\nUsage: comment push <post> <time> <author> <content>...")
|
|
}
|
|
body = Object.assign([], arg)
|
|
body.shift()
|
|
body.shift()
|
|
body.shift()
|
|
body.shift()
|
|
|
|
let time = arg[2]
|
|
if (arg[2] == "auto") {
|
|
time = new Date().getTime()
|
|
console.log( "Auto-time: using time: " + time)
|
|
}
|
|
console.log( arg[3] )
|
|
console.log( comments.push(arg[1], {
|
|
"time": time,
|
|
"author":arg[3].replace(/%20/g, " "),
|
|
"authorinfo":{"origin":"console"},
|
|
"body": body.join(" ").replace(/\\n/g, "\n")
|
|
}) )
|
|
break
|
|
|
|
case "delete":
|
|
if ( !arg[1] || !arg[2] ) return console.log("Usage \"post delete <postID> <commentID>\"")
|
|
console.log(comments.delete( arg[1], arg[2] ))
|
|
break
|
|
|
|
case "set": // DONT USE! its broken
|
|
if ( !arg[1] ) return console.log("No post ID specified!")
|
|
if ( !arg[2] ) return console.log("No comment specified!")
|
|
|
|
body = Object.assign([], arg[3])
|
|
body.shift()
|
|
body.shift()
|
|
|
|
console.log( comments.set( arg[1], arg[2], { "body":body.join(" ") } ) )
|
|
break
|
|
|
|
case "sync":
|
|
console.log("syncing...")
|
|
t = commentDB.sync()
|
|
if (t) console.log(t)
|
|
console.log("DONE!")
|
|
break
|
|
|
|
default:
|
|
console.log("Sub-command not found or not supplied!")
|
|
|
|
|
|
case "?":
|
|
case "h":
|
|
case "help":
|
|
console.log("Availible cmds: get, sync, push, set, delete")
|
|
break
|
|
}
|
|
}))
|
|
|
|
con.registercmd( "post", (arg => {
|
|
let t
|
|
sw:
|
|
switch (arg[0]) {
|
|
case "get":
|
|
if (!arg[1]) {
|
|
console.log("Nothing to get!")
|
|
} else {
|
|
console.log(postsDB.get(arg[1]))
|
|
}
|
|
break
|
|
|
|
case "ranking":
|
|
if (arg[1]) {
|
|
console.log(posts.ranking[arg[1]])
|
|
break sw
|
|
} else {
|
|
let keys = Object.keys(posts.ranking)
|
|
for ( let i = 0 ; i < keys.length ; i++ ) {
|
|
console.log(keys[i] + ":")
|
|
console.log(posts.ranking[keys[i]])
|
|
}
|
|
break sw
|
|
}
|
|
|
|
case "rank":
|
|
console.log("Ranking...")
|
|
t = posts.rank()
|
|
if (t) console.log(t)
|
|
console.log("DONE!")
|
|
break
|
|
|
|
case "sync":
|
|
console.log("syncing...")
|
|
t = postsDB.sync()
|
|
if (t) console.log(t)
|
|
console.log("DONE!")
|
|
break
|
|
|
|
case "index":
|
|
console.log("indexing...")
|
|
t = posts.index()
|
|
if (t) console.log(t)
|
|
console.log("DONE!")
|
|
break
|
|
|
|
default:
|
|
console.log("Sub-command not found or not supplied!")
|
|
|
|
|
|
case "?":
|
|
case "h":
|
|
case "help":
|
|
console.log("Availible cmds: get, ranking, rank, sync, index")
|
|
break
|
|
}
|
|
}))
|
|
|
|
// shutdown:
|
|
function shutdown() {
|
|
log.log("Shutting down", log.d.basic)
|
|
log.clearBUFF()
|
|
|
|
postsDB.sync()
|
|
commentDB.sync()
|
|
|
|
process.exit(1)
|
|
}
|
|
|
|
// readout jsonDB:
|
|
const postsDB = new JSONdb("storage/posts.json", {
|
|
"syncOnWrite":conf.post_sync_on_write
|
|
})
|
|
posts.init(postsDB)
|
|
posts.rank()
|
|
posts.index() // for search
|
|
|
|
// post auto rank
|
|
if ( conf.post_auto_rank > 0)
|
|
scheduler.schedule(() => {
|
|
posts.rank()
|
|
posts.index()
|
|
log.log("autolranking posts", log.d.basic)
|
|
}, conf.post_ranking_auto)
|
|
|
|
// ip-rating "user"/
|
|
// => You can only rate an article once per ip
|
|
posts.IPs = {}
|
|
// see posts.js
|
|
|
|
// readout comments:
|
|
const commentDB = new JSONdb("storage/comments.json", {
|
|
"syncOnWrite":conf.comment_sync_on_write
|
|
})
|
|
comments.init(commentDB)
|
|
|
|
// posts:
|
|
app.get("/posts", (req, res) => {
|
|
if( typeof( req.query.api ) != "undefined" ) {
|
|
res.type( "application/json" )
|
|
let len = req.query.len ? req.query.len : 10
|
|
let index = req.query.page ? req.query.page * len : 0
|
|
let pagecount = Math.floor( postsDB.get("len") / len)
|
|
|
|
if( typeof( req.query.hot ) != "undefined" ) {
|
|
if( ! ( req.query.len < 50 ) ) {
|
|
res.status( 400 )
|
|
res.end( JSON.stringify({"type":"err","text":"no len or to high specified"}) )
|
|
} else {
|
|
res.status( 200 )
|
|
log.log(`Reading posts sorted by "hot" with a length of ${len}`, log.d.datahorder)
|
|
res.end(`{"type":"s","pages":${pagecount},"content":${JSON.stringify(posts.read(len, "hot"), index)}}`)
|
|
}
|
|
} else if ( typeof( req.query.new ) != "undefined" ) {
|
|
if( ! ( req.query.len < 50 ) ) {
|
|
res.status( 400 )
|
|
res.end( JSON.stringify({"type":"err","text":"no len or to high specified"}) )
|
|
} else {
|
|
res.status( 200 )
|
|
log.log(`Reading posts sorted by "new" with a length of ${len}`, log.d.datahorder)
|
|
res.end(`{"type":"s","pages":${pagecount},"content":${JSON.stringify(posts.read(len, "new", index))}}`)
|
|
}
|
|
}
|
|
} else {
|
|
if( typeof(req.query.post) != "undefined" ) {
|
|
res.status( 200 )
|
|
log.log(`Reading post ${req.query.post}`, log.d.datahorder)
|
|
filestuff.readFSr(req, res, "html/posts/index.html", "text/html", `""//<!--POST-DATA-INJECT-->//`, JSON.stringify(postsDB.get(req.query.post)))
|
|
} else {
|
|
let sort = "hot"
|
|
if ( typeof(req.query.sort) != "undefined" ) {
|
|
sort = req.query.sort
|
|
if( !["hot","new","rit"].includes( req.query.sort ) ) {
|
|
res.end("FUCK YOU!")
|
|
return
|
|
}
|
|
}
|
|
res.status( 200 )
|
|
log.log(`Reading postindex`, log.d.datahorder)
|
|
filestuff.readFSr(req, res, "html/posts/index.list.html", "text/html", `""//<!--SORT-INJECT-->//`, sort)
|
|
}
|
|
}
|
|
})
|
|
|
|
// comments:
|
|
app.use(express.json())
|
|
app.use(express.urlencoded({extended: true}))
|
|
app.all("/comments", (req, res) => { // + rating
|
|
res.type("application/json")
|
|
let ret
|
|
let waiting
|
|
if ( req.body.body && req.body.ip && req.body.post && conf.commenting_enabled ) {
|
|
console.log("commentetded!")
|
|
// get ip from tkn
|
|
waiting = true
|
|
fetch("https:" + conf.ipget_endpoint_get.replace("${TOKEN}", req.body.ip)).then(
|
|
d => d.text()).then(data=>{
|
|
log.log(`Trying to comment to post "${req.body.post}", from ip "${data}" (tkn: ${req.body.ip}) with content: "${req.body.body}"`, log.d.datahorder)
|
|
if (data == "") {
|
|
res.end(JSON.stringify({"type":"err","text":"ip-tkn"}))
|
|
return
|
|
}
|
|
ret = comments.push(req.body.post, {
|
|
"time": new Date().getTime(),
|
|
"author":data,
|
|
"authorinfo":{
|
|
"country":geoip.lookupCountry(data),
|
|
"origin":"web"
|
|
},
|
|
"body": req.body.body.replace(/\</g, "<").replace(/\>/g, ">")
|
|
})
|
|
if ( ret.type == "err" ) res.status( 400 )
|
|
setTimeout(() => {
|
|
res.end(JSON.stringify( ret ))
|
|
}, 10)
|
|
})
|
|
}
|
|
|
|
if ( req.query.post && req.query.rate == undefined ) {
|
|
ret = comments.get(req.query.post, req.query.len ? req.query.len : undefined, undefined)
|
|
log.log(`Reading comments from post "${req.query.post}", with length: ${req.query.len}`)
|
|
if ( ret.type == "err" ) res.status( 400 )
|
|
res.end( JSON.stringify(ret) )
|
|
}
|
|
|
|
if ( req.query.rate != undefined && req.query.post && req.query.rating && req.query.ip ) {
|
|
waiting = true
|
|
fetch("https:" + conf.ipget_endpoint_get.replace("${TOKEN}", req.query.ip)).then(
|
|
(d) => d.text()).then(data => {
|
|
log.log("Trying to vote on post: "+req.query.post+"; and vote: "+req.query.rating+"; iptkn: "+req.query.ip+"; ip: " +data+";", log.d.datahorder)
|
|
if ( data == "" ) {
|
|
res.end(JSON.stringify({"type":"err","text":"ip-tkn"}))
|
|
} else {
|
|
let ret = posts.rate( req.query.post, req.query.rating, data )
|
|
res.end( JSON.stringify( ret ) )
|
|
}
|
|
})
|
|
}
|
|
|
|
if ( !res.finished && !waiting ) {
|
|
res.status ( 501 )
|
|
res.end(JSON.stringify({"type":"err","text":"not implemented!"}))
|
|
}
|
|
})
|
|
|
|
// search stuff:
|
|
if ( conf.search_enable ) {
|
|
con.registercmd("search", (arg) => {
|
|
if ( !arg[0] || !arg[1] ) return console.log( "No search parameters specified!\nusage: \"search <sort> <param1> <param2>...\"" )
|
|
let sort = arg[0]
|
|
arg.shift()
|
|
console.log( posts.search( arg, sort ) )
|
|
})
|
|
app.get("/search", (req, res) => {
|
|
let tags = req.query.tag ? req.query.tag.split(" ") : []
|
|
let author = req.query.author ? req.query.author.split(" ") : []
|
|
let sort = req.query.sort ? req.query.sort : undefined
|
|
|
|
if ( tags.length == 0 && author.length == 0 ) {
|
|
res.status( 400 )
|
|
if ( req.query.api != undefined ) {
|
|
res.type("application/json")
|
|
res.end( JSON.stringify( {"type":"err","text":"NO SEARCH PARAMS"} ) )
|
|
return
|
|
} else {
|
|
res.end("No search params")
|
|
return
|
|
}
|
|
}
|
|
|
|
if ( req.query.api == undefined ) {
|
|
let r = {}
|
|
r.sd = posts.search( tags, author, sort, true )
|
|
r.arg = tags
|
|
|
|
filestuff.readFSr(req, res, "html/search/index.html", "text/html", `""//<!--SEARCH-DATA-INJECT-->//`, JSON.stringify( r ) )
|
|
return
|
|
}
|
|
log.log( `searching stuff by tags "${req.query.tag}" and sorting "${req.query.sort}"` )
|
|
|
|
// actual api
|
|
res.type("application/json")
|
|
|
|
// check is post info is needed:
|
|
let p = req.query.pi != undefined
|
|
|
|
// construct response
|
|
let r = {"type":"s","text":"success!"}
|
|
r.content = posts.search( tags, author, sort, p )
|
|
|
|
res.end( JSON.stringify( r ) )
|
|
})
|
|
} else {
|
|
app.get("/search", (req, res) => filestuff.readFS(req,res,"html/search/disabled.html","text/html"))
|
|
}
|
|
|
|
// admin stuff:
|
|
admin.init(comments, posts, log)
|
|
con.registercmd( "passwd", (arg) => {
|
|
if ( !arg[0] ) return console.log( "Usage: \"passwd <pass>\"" )
|
|
console.log( admin.setpass( arg[0] ) )
|
|
})
|
|
con.registercmd( "testpass", (arg) => {
|
|
if ( !arg[0] ) return console.log("Usage: \"testpass <pass>\"")
|
|
console.log( admin.pass( arg[0] ) )
|
|
})
|
|
app.use("/admin/", (req, res, next) => admin.pre(req, res, next))
|
|
app.get("/admin", (req, res) => filestuff.readFS(req, res, "html/admin/index.html", "text/html"))
|
|
app.post("/admin/post", (req, res) => admin.post(req, res))
|
|
|
|
app.listen(conf.listening_port, conf.listening_addr, () => {
|
|
console.log(`Server listening on http://${conf.listening_addr}:${conf.listening_port}`)
|
|
if(conf.cl) con.init()
|
|
})
|