400 lines
13 KiB
TypeScript
400 lines
13 KiB
TypeScript
console.log(`
|
|
|
|
_ _ _ _
|
|
| |_____| |____ __ __ ____ _| |_ ___ ___ _ _ ___| |_
|
|
| / / -_) / /\ V V /(_-< || | _/ -_|_-<_| ' \/ -_) _|
|
|
|_\_\___|_\_\ \_/\_(_)__/\_, |\__\___/__(_)_||_\___|\__|
|
|
|__/
|
|
|
|
`);
|
|
const gitdir = "/home/"
|
|
|
|
import { existsSync,readFileSync, writeFileSync,mkdirSync,unlinkSync,rmSync,readdirSync} from "fs";
|
|
import gemini, { Request, Response, TitanRequest, NextFunction } from "gemini-server";
|
|
import { Sequelize, DataTypes } from "sequelize";
|
|
process.title = "gemini-server"
|
|
const {gitToJs} = require("git-parse")
|
|
const options = {
|
|
cert: readFileSync("cert.pem"),
|
|
key: readFileSync("key.pem"),
|
|
titanEnabled: true,
|
|
};
|
|
try{
|
|
mkdirSync("tmp")
|
|
//mkdirSync("git")
|
|
}catch(e){}
|
|
const app = gemini(options);
|
|
let git = readdirSync(gitdir+"git")
|
|
const sequelize = new Sequelize({
|
|
dialect: 'sqlite',
|
|
storage: 'sql/forums.sqlite',
|
|
logging: false
|
|
});
|
|
|
|
const forums = sequelize.define('forums', {
|
|
topic: {
|
|
type: DataTypes.STRING,
|
|
allowNull: false
|
|
},
|
|
created: {
|
|
type: DataTypes.STRING,
|
|
allowNull: false
|
|
},
|
|
thread:{
|
|
type: DataTypes.STRING,
|
|
allowNull: false,
|
|
|
|
}
|
|
}, {});
|
|
//make sure it exists
|
|
(async()=>{
|
|
sequelize.sync();
|
|
/*
|
|
await sequelize.sync({force:true}); // clear table
|
|
let thread2 = await forums.create({topic:"test2",created:"time",thread:[]})
|
|
thread2.set({
|
|
topic:"test33",
|
|
thread:[{
|
|
"hello":"world",
|
|
"main":"test4",
|
|
"comments":[]
|
|
},],
|
|
})
|
|
thread2.save()
|
|
sequelize.sync({alter:true})
|
|
*/
|
|
})()
|
|
function datefmt (date:any, fstr:any, utc:any) {
|
|
utc = utc ? 'getUTC' : 'get';
|
|
return fstr.replace (/%[YmdHMS]/g, function (m:any) {
|
|
switch (m) {
|
|
case '%Y': return date[utc + 'FullYear'] (); // no leading zeros required
|
|
case '%m': m = 1 + date[utc + 'Month'] (); break;
|
|
case '%d': m = date[utc + 'Date'] (); break;
|
|
case '%H': m = date[utc + 'Hours'] (); break;
|
|
case '%M': m = date[utc + 'Minutes'] (); break;
|
|
case '%S': m = date[utc + 'Seconds'] (); break;
|
|
default: return m.slice (1); // unknown code, remove %
|
|
}
|
|
// add leading zero if required
|
|
return ('0' + m).slice (-2);
|
|
});
|
|
}
|
|
app.use(async(_req: Request, res: Response) => {
|
|
if(_req.url.pathname.includes('/git')){
|
|
let gitlist = ''
|
|
for(let g of git){
|
|
gitlist += "=> gemini://"+_req.url.host+"/git/"+g+" "+g+"\n"
|
|
}
|
|
if(_req.url.pathname=='/git'||_req.url.pathname=='/git/'){
|
|
let a:any = Math.random()
|
|
let t = readFileSync("./pages/git.gemini").toString().replace(/{git-list}/g,gitlist).replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
return;
|
|
} else {
|
|
let reqd = ''
|
|
for(let g of git){
|
|
if(_req.url.pathname.split("/")[2].includes(g)||_req.url.pathname.split("/")[2].includes(g+"/")){
|
|
reqd = g
|
|
break
|
|
}
|
|
}
|
|
if(reqd==''){
|
|
let a:any = Math.random()
|
|
let t = readFileSync("./pages/404.gemini").toString().replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
return
|
|
} else {
|
|
if(_req.url.pathname.split("/")[3]==undefined){
|
|
let parsedGit
|
|
try{
|
|
parsedGit = await gitToJs(gitdir+_req.url.pathname)
|
|
} catch (e){
|
|
res.data("not a valid git page")
|
|
return;
|
|
}
|
|
let a:any = Math.random()
|
|
let cList = ''
|
|
for(let commit of parsedGit){
|
|
cList +=`\n=> gemini://${_req.url.host}${_req.url.pathname}/${commit.hash} ${commit.authorName} ${commit.hash.substring(0, 9)}... "${commit.message}" ${commit.date} `
|
|
for(let i of commit.filesAdded){
|
|
cList += '+'
|
|
}
|
|
for(let i of commit.filesDeleted){
|
|
cList += '-'
|
|
}
|
|
for(let i of commit.filesModified){
|
|
cList += '~'
|
|
}
|
|
for(let i of commit.filesRenamed){
|
|
cList += '~'
|
|
}
|
|
}
|
|
let readme = ''
|
|
if(existsSync(gitdir+_req.url.pathname+'/readme')){
|
|
readme = '\n\n## readme\n\n'+readFileSync(gitdir+_req.url.pathname+'/readme').toString()
|
|
}
|
|
if(existsSync(gitdir+_req.url.pathname+'/readme.md')){
|
|
readme = '\n\n## readme\n\n'+readFileSync(gitdir+_req.url.pathname+'/readme.md').toString()
|
|
}
|
|
let t = `=> gemini://${_req.url.host+_req.url.pathname}/source source\n\n#${reqd}${readme}\n\n## commits\n${cList}`
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
|
|
} else {
|
|
let x = (_req.url.pathname.split('/'))
|
|
let z = x.splice(3,1)
|
|
let parsedGit
|
|
try{
|
|
parsedGit = await gitToJs(gitdir+x.join('/'))
|
|
} catch(e){
|
|
parsedGit = []
|
|
}
|
|
let a:any = Math.random()
|
|
let cList:any = []
|
|
for(let commit of parsedGit){
|
|
if(z == commit.hash){
|
|
let t = `# commit ${commit.hash}\n\n`
|
|
for(let i of commit.filesAdded){
|
|
i['action']='add'
|
|
cList.push(i)
|
|
}
|
|
for(let i of commit.filesDeleted){
|
|
i['action']='del'
|
|
cList.push(i)
|
|
}
|
|
for(let i of commit.filesModified){
|
|
i['action']='mod'
|
|
cList.push(i)
|
|
}
|
|
for(let i of commit.filesRenamed){
|
|
i['action']='mv'
|
|
cList.push(i)
|
|
}
|
|
for(let ch of cList){
|
|
if(ch.action=='add'){
|
|
t+=`+${ch.path}\n`
|
|
}
|
|
if(ch.action=='del'){
|
|
t+=`-${ch.path}\n`
|
|
}
|
|
if(ch.action=='mod'){
|
|
t+=`~${ch.path}\n`
|
|
}
|
|
if(ch.action=='mv'){
|
|
t+=`${ch.oldPath}->${ch.newPath}\n`
|
|
}
|
|
}
|
|
t+=`\n## info\n\nauthor - ${commit.authorName} (${commit.authorEmail})\ndate - ${commit.date}\nmessage - ${commit.message}`
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
return
|
|
}
|
|
}
|
|
x = (_req.url.pathname.split('/'))
|
|
|
|
z = x.splice(3,1)
|
|
let def = x
|
|
let aaa = '';
|
|
for(let l of def){
|
|
aaa+=l+"/"
|
|
}
|
|
let aa = aaa.split('/')
|
|
aa.splice(3,0,z.join(""))
|
|
let bbb = '';
|
|
for(let l of def){
|
|
bbb+=l+"/"
|
|
}
|
|
let bb = bbb.split('/')
|
|
for(let n of bb){
|
|
if(n==''){
|
|
bb.splice(bb.indexOf(n),1)
|
|
}
|
|
}
|
|
if(!(bb.length==2)){
|
|
bb.splice(bb.length-1,1)
|
|
if(!bb.includes("source")){
|
|
bb.splice(2,0,"source")
|
|
}
|
|
}
|
|
|
|
//bb.splice(bb.length,1)
|
|
if(z.join("").includes('source')){
|
|
var ignore:string[];
|
|
try{
|
|
let gitDir = readdirSync(gitdir+x.join("/"))
|
|
try{
|
|
ignore = readFileSync(gitdir+x.join("/")+"/.gitignore").toString().split("\n")
|
|
} catch(e){
|
|
ignore = [];
|
|
}
|
|
|
|
//let t = `=> gemini://${_req.url.host+x.join('/')} ${x.join('/')}\n\n`
|
|
let t = `=> gemini://${_req.url.host}${_req.url.pathname} [d] .\n=> gemini://${_req.url.host}/${bb.join("/") } [d] ..\n`
|
|
for(let i of gitDir){
|
|
|
|
if(!ignore.includes(i)){
|
|
try{
|
|
//! may try to append an extra "/" (maybe?)
|
|
readFileSync(gitdir+x.join("/")+"/"+i)
|
|
t += `=> gemini://${_req.url.host+aa.join("/")+i} ${i}\n`
|
|
} catch(e) {//is directory
|
|
t += `=> gemini://${_req.url.host+aa.join("/")+i} [d] ${i}\n`
|
|
}
|
|
}
|
|
}
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
return
|
|
}catch (e) {//a file
|
|
try{
|
|
let a:any = Math.random()
|
|
let f = (readFileSync(gitdir+x.join("/")).toString())
|
|
writeFileSync("tmp/"+a+".gemini",f)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
return
|
|
} catch(e){
|
|
let t = readFileSync("./pages/404.gemini").toString().replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
return
|
|
}
|
|
|
|
}
|
|
}
|
|
let t = readFileSync("./pages/404.gemini").toString().replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
return
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
} else if(_req.url.pathname.includes('/forums')) {
|
|
if(_req.url.pathname=="/forums"){
|
|
let a:any = Math.random()
|
|
let topics = await forums.findAll()
|
|
let top = ''
|
|
for(let topic of topics){
|
|
top+=`=> gemini://${_req.url.host}/${_req.url.pathname}/${topic.getDataValue('id')} ${topic.getDataValue('topic')}\n`
|
|
}
|
|
|
|
let t= readFileSync("./pages/forums.gemini").toString().replace(/{domain}/g,_req.url.host).replace(/{forums}/g,top)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
|
|
} else if(_req.url.pathname=="/forums/submissive"){
|
|
|
|
|
|
if(_req.query!=null){
|
|
_req.query=_req.query+''
|
|
_req.query=decodeURI(_req.query)
|
|
let thread = await forums.create({topic:_req.query,created:datefmt(new Date(),"%Y-%m-%d %H:%M:%S", true),thread:"[]"})
|
|
thread.save()
|
|
sequelize.sync({alter:true})
|
|
res.redirect(thread.getDataValue('id')+'')
|
|
return
|
|
} else {
|
|
res.input("forum name")
|
|
return
|
|
}
|
|
} else {
|
|
let foru = _req.url.pathname.split('/forums/')[1]
|
|
//console.log(foru)
|
|
|
|
let all = await forums.findAll()
|
|
let id = parseInt(foru)
|
|
//for()
|
|
// // @ts-ignore
|
|
for(let a of all){
|
|
if(a.getDataValue('id')==id){
|
|
if(foru.split('/').length>=2){
|
|
//extra command TwT
|
|
if(_req.query!=null){
|
|
_req.query=_req.query+''
|
|
_req.query=decodeURI(_req.query)
|
|
let parse = (JSON.parse(a.getDataValue('thread')))
|
|
parse[parse.length]={m:_req.query,date:datefmt(new Date(),"%Y-%m-%d %H:%M:%S", true)}
|
|
a.setDataValue('thread',JSON.stringify(parse))
|
|
a.save()
|
|
sequelize.sync({alter:true})
|
|
viewForum(res,_req,a)
|
|
return
|
|
|
|
} else {
|
|
res.input("comment")
|
|
return
|
|
}
|
|
} else {
|
|
viewForum(res,_req,a)
|
|
}
|
|
return
|
|
}
|
|
|
|
|
|
}
|
|
// !404
|
|
}
|
|
|
|
}else {
|
|
let a:any = Math.random()
|
|
let t = readFileSync("./pages/404.gemini").toString().replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
}
|
|
|
|
});
|
|
function viewForum(res:any,_req:any,a:any){
|
|
let z = Math.random()
|
|
//console.log(a.getDataValue('thread'))
|
|
let com = ''
|
|
for(let c of (JSON.parse(a.getDataValue('thread')))){
|
|
com+=`\n### ${c.date}\n\n${c.m}\n__________`
|
|
}
|
|
let s = (`# ${a.dataValues.topic}\n\nlast - ${a.dataValues.createdAt}\nupdated - ${a.dataValues.updatedAt}\n\n=> gemini://${_req.url.host}${_req.url.pathname}/sub comment\
|
|
\n\n## thread\n\n${com}`)
|
|
writeFileSync("tmp/"+z+".gemini",s)
|
|
res.file("tmp/"+z+".gemini");
|
|
unlinkSync("tmp/"+z+".gemini")
|
|
}
|
|
app.on("/", (_req: Request, res: Response) => {
|
|
let a:any = Math.random()
|
|
let t = readFileSync("./pages/index.gemini").toString().replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
});
|
|
|
|
app.on("/aboutme", (_req: Request, res: Response) => {
|
|
let a:any = Math.random()
|
|
let t = readFileSync("./pages/aboutme.gemini").toString().replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
});
|
|
app.on("/ascii", (_req: Request, res:Response) => {
|
|
let a:any = Math.random()
|
|
let t = readFileSync("./pages/ascii.gemini").toString().replace(/{domain}/g,_req.url.host)
|
|
writeFileSync("tmp/"+a+".gemini",t)
|
|
res.file("tmp/"+a+".gemini");
|
|
unlinkSync("tmp/"+a+".gemini")
|
|
})
|
|
app.listen(() => {
|
|
console.log("Listening...");
|
|
});
|
|
process.on('exit', function (code) {
|
|
rmSync("tmp", { recursive: true, force: true })
|
|
}); |