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 }) });