Skip to content

Instantly share code, notes, and snippets.

@Lightnet
Created September 16, 2023 02:11
Show Gist options
  • Save Lightnet/1897bb1a38bc87128bfc97630d4092c1 to your computer and use it in GitHub Desktop.
Save Lightnet/1897bb1a38bc87128bfc97630d4092c1 to your computer and use it in GitHub Desktop.

Using the https://vanjs.org/ to render html and javascript client build for gun.js

Features:

  • server minimalist
    • node js
  • user ui
    • login
    • register
    • forgot
    • change passphrase
    • forgot hint
{
"name": "node_van_js",
"version": "1.0.0",
"description": "",
"main": "server.js",
"type": "module",
"scripts": {
"start": "node server.js",
"dev": "node server.js",
"dev0": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"gun": "^0.2020.1239",
"mini-van-plate": "^0.4.0"
}
}
// https://stackoverflow.com/questions/16333790/node-js-quick-file-server-static-files-over-http
import * as url from 'url';
//import fs from 'fs';
import fs, { existsSync } from 'node:fs';
//import fs from 'node:fs';
import path from 'node:path';
import http from 'http';
import Gun from 'gun';
import van from "mini-van-plate/van-plate";
const {a, div, body, script, button, input, li, p, ul} = van.tags
const __filename = url.fileURLToPath(import.meta.url);
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
//console.log(Gun.serve(__dirname));
function web_hander(req, res){
//console.log(`${req.method} ${req.url}`);
// parse URL
const parsedUrl = url.parse(req.url);
// extract URL path
let pathname = `.${parsedUrl.pathname}`;
// based on the URL path, extract the file extension. e.g. .js, .doc, ...
const ext = path.parse(pathname).ext;
// maps file extension to MIME typere
const map = {
'.ico': 'image/x-icon',
'.html': 'text/html',
'.js': 'text/javascript',
'.json': 'application/json',
'.css': 'text/css',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.wav': 'audio/wav',
'.mp3': 'audio/mpeg',
'.svg': 'image/svg+xml',
'.pdf': 'application/pdf',
'.doc': 'application/msword'
};
//existsSync(pathname, function (exist) {
let fileExist = existsSync(pathname);
if (fileExist){
if(!fileExist) {
// if the file is not found, return 404
res.statusCode = 404;
res.end(`File ${pathname} not found!`);
return;
}
// if is a directory search for index file matching the extension
if (fs.statSync(pathname).isDirectory()) pathname += '/index' + ext;
// read file from file system
fs.readFile(pathname, function(err, data){
if(err){
res.statusCode = 500;
res.end(`Error getting the file: ${err}.`);
} else {
// if the file is found, set Content-type and send data
res.setHeader('Content-type', map[ext] || 'text/plain' );
res.end(data);
}
});
}
if(req.url == "/"){
res.writeHead(200, {'Content-Type': 'text/html'});
//res.write('Hello World!');
//res.end();
res.end(van.html(
body(
//p("Your user-agent is: ", req.headers["user-agent"] ?? "Unknown"),
//p("Hello"),
//ul(
//li("World"),
//li(a({href: "https://vanjs.org/"}, "VanJS")),
//),
script({type:"module",src:"/user.js"}),
),
));
}
}
function main(){
let PORT = 3000;
//const server = http.createServer(Gun.serve(__dirname));
const server = http.createServer(web_hander);
server.listen(PORT);
var gun = Gun({web: server});
gun.on("hi", peer => {
//peer connect
//console.log('connect peer to',peer);
console.log("peer connect!");
});
gun.on("bye", peer => {
// peer disconnect
//console.log('disconnected from', peer);
console.log("disconnected from peer!");
});
console.log(`node server... http://localhost:${PORT}`);
console.log('Relay peer started on port ' + PORT + ' with /gun');
}
main();
import van from "https://cdn.jsdelivr.net/gh/vanjs-org/van/public/van-1.2.0.min.js";
//import Gun from "https://cdn.jsdelivr.net/npm/gun/gun.js";
import GUN from "https://cdn.skypack.dev/gun";
import SEA from "https://cdn.skypack.dev/gun/sea";
const {span, br, div,label, body, script, button, input, li, p, ul, a} = van.tags;
const gun = GUN(location.origin+"/gun");
//make sure it connected
gun.on("hi", peer => {
//peer connect
//console.log('connect peer to',peer);
console.log("peer connect!");
});
gun.on("bye", peer => {
// peer disconnect
//console.log('disconnected from', peer);
console.log("disconnected from peer!");
});
//===============================================
// ACCESS PAGE
//===============================================
const LoginEL = () =>{
const alias = van.state('test');
const passphrase = van.state('12345678');
function click_login(){
const user = gun.user();
user.auth(alias.val, passphrase.val, (ack)=>{
if(ack.err){
console.log("ERROR: ", ack.err);
return;
}
//console.log(ack)
document.getElementById("login").remove();
van.add(document.body, HomeEL())
});
}
function click_register(){
console.log("Register")
const user = gun.user();
//user.create(alias, pass, cb, opt)
user.create(alias.val, passphrase.val,(ack)=>{
if(ack.err){
console.log("ERROR: ", ack.err);
return;
}
console.log(ack)
})
}
function click_forgot(){
document.getElementById("login").remove();
van.add(document.body, ForgotEL())
}
return div(
{id:"login"},
label('Alias:'),
input({placeholder:"User Name",value:alias, oninput: e=>alias.val = e.target.value}),
label('Passphrase:'),
input({placeholder:"Password / Passphrase",value:passphrase, oninput: e=>passphrase.val = e.target.value}),
button({onclick:()=>click_login()},'Login'),
button({onclick:()=>click_register()},'Register'),
button({onclick:()=>click_forgot()},'Forgot'),
)
};
const ForgotEL = ()=>{
const alias = van.state('test');
const question1 = van.state('');
const question2 = van.state('');
const hint = van.state('');
async function click_get_hint(){
console.log(gun);
console.log(alias.val);
console.log('alias/'+alias.val)
let graph = await gun.get('~@'+alias.val)
console.log(graph)
let publickey;
for(let obj in graph){//object
//console.log(obj);
//property name for public key
if(SEA.opt.pub(obj)){//check if alias pub key
publickey = SEA.opt.pub(obj);
break;
}
}
if(!publickey){
console.log("PUB KEY NULL!");
return;
}
console.log("Alias Pub: ", publickey);
let to = gun.user(publickey);//get user alias graph
let _hint = await to.get('hint').then();//get encrypt hint key graph
let dec = await Gun.SEA.work(question1.val,question2.val);//get fquestion1 and fquestion2 string to mix key
_hint = await Gun.SEA.decrypt(_hint,dec);//get hint and key decrypt message
if(_hint){
hint.val = _hint;
}else{
console.log("FAIL HINT")
}
}
function click_back(){
document.getElementById("forgot").remove();
van.add(document.body, LoginEL())
}
return div(
{id:'forgot'},
label('Alias:'),
input({placeholder:"User Name",value:alias, oninput: e=>alias.val = e.target.value}),
br(),
label('Question #1:'),
input({placeholder:"Question No.1",value:question1, oninput: e=>question1.val = e.target.value}),
br(),
label('Question #2:'),
input({placeholder:"Question No.2",value:question2, oninput: e=>question2.val = e.target.value}),
br(),
label('Hint:'),
input({placeholder:"Hint",value:hint, oninput: e=>hint.val = e.target.value}),
br(),
button({onclick:()=>click_get_hint()},'Get Hint'),
button({onclick:()=>click_back()},'Back'),
)
}
//document.body.appendChild(LoginEL());
van.add(document.body, LoginEL())
//===============================================
// HOME PAGE
//===============================================
const HomeEL = () =>{
const view = van.state('account');
function click_logout(){
const user = gun.user();
user.leave();
document.getElementById("home").remove();
van.add(document.body, LoginEL())
}
return div(
{id:"home"},
div(
button({onclick:()=>view.val='account'},'Account'),
button({onclick:()=>view.val='message'},'Message'),
button({onclick:()=>view.val='chat'},'Chat'),
button({onclick:()=>click_logout()},'Logout'),
PubDisplayEL()
),
van.derive(()=>{
if(view.val == 'account'){
return AccountEL();
}
if(view.val == 'message'){
return div(
label('Message')
)
}
if(view.val == 'chat'){
return div(
label('Chat')
)
}
})
);
};
const AccountEL = () =>{
const view = van.state('profile');
return div(
{id:'account'},
div(
button({onclick:()=>view.val='profile'},'Profile'),
button({onclick:()=>view.val='changepassphrase'},'Change Passphrase'),
button({onclick:()=>view.val='changequestions'},'Change Questions'),
button({onclick:()=>view.val='certs'},'Certs'),
),
van.derive(()=>{
if(view.val == 'profile'){
return ProfileEL()
}
if(view.val == 'changepassphrase'){
return ChnagePassphraseEL()
}
if(view.val == 'changequestions'){
return ChnageQuestionsEL()
}
if(view.val == 'certs'){
return CertsEL()
}
}),
)
}
const ProfileEL = () =>{
const alias = van.state('Guest');
const pub = van.state('Public Key');
const user = gun.user();
//console.log(user);
if(user.is.alias){
alias.val = user.is.alias;
pub.val = user.is.pub;
}
return div({id:'profile'},
label('Profile'),
br(),
label('Alias:'+alias.val),
br(),
label('Pub: '+pub.val),
)
};
const PubDisplayEL = ()=>{
const alias = van.state('Guest');
const pub = van.state('Public Key');
const user = gun.user();
if(user?.is?.alias){
alias.val = user.is.alias;
pub.val = user.is.pub;
}
function click_copy(){
navigator.clipboard.writeText(pub.val);
//alert("Copied the text: " + pub.val);
}
return span(
label(' Alias:'),
label('[ '+alias.val+' ]'),
label({onclick:()=>click_copy()},' [Pub Key Copy]: '),
input({value:pub.val})
)
}
const ChnagePassphraseEL = () =>{
const oldPassphrase = van.state('');
const newPassphrase = van.state('');
function click_apply(){
//console.log(oldPassphrase.val + " > " + newPassphrase.val);
const user = gun.user();
user.auth(user.is.alias,oldPassphrase.val,(ack)=>{
if(ack.err){
console.log("ERROR: ",ack.err)
return;
}
console.log(ack);
//console.log("PASSWORD CHANGE...")
},{change:newPassphrase.val})
}
return div({id:'changepassphrase'},
label('Change Passphrase'),
br(),
label('Old passphrase:'),
input({value:oldPassphrase, oninput:e=>oldPassphrase.val=e.target.value}),
br(),
label('New passphrase:'),
input({value:newPassphrase, oninput:e=>newPassphrase.val=e.target.value}),
button({onclick:()=>click_apply()},'Apply'),
)
};
const ChnageQuestionsEL = () =>{
const question1 = van.state('');
const question2 = van.state('');
const hint = van.state('');
async function click_apply_hint(){
//console.log(oldPassphrase.val + " > " + newPassphrase.val);
const user = gun.user();
//console.log(user);
const pair = user._.sea;
let enc = await SEA.encrypt(question1.val, pair);
//console.log("question1:",enc);
user.get('question1').put(enc);
let enc1 = await SEA.encrypt(question2.val, pair);
//console.log("question2:",enc1);
user.get('question2').put(enc1);
let enc2 = await SEA.work(question1.val, question2.val);
let data = await SEA.encrypt(hint.val, enc2);
//console.log("HINT:",data)
user.get('hint').put(data);
}
async function click_get_hint(){
//console.log(oldPassphrase.val + " > " + newPassphrase.val);
const user = gun.user();
const pair = user._.sea;
let q1 = await user.get('question1').then();
//console.log("q1: ", q1);
q1 = await SEA.decrypt(q1, pair);
//console.log('q1: ', q1);
question1.val = q1;
let q2 = await user.get('question2').then();
//console.log("q2: ", q2);
q2 = await SEA.decrypt(q2, pair);
question2.val = q2;
//console.log('q2: ', q2);
let sec = await SEA.work(q1, q2);
let hint0 = await user.get('hint').then();
//console.log("hint: ", hint);
hint0 = await SEA.decrypt(hint0, sec);
//console.log(hint0)
hint.val = hint0;
}
return div({id:'changequestions'},
label('Change Questions'),
br(),
label('Question #1:'),
input({value:question1, oninput:e=>question1.val=e.target.value}),
br(),
label('Question #2:'),
input({value:question2, oninput:e=>question2.val=e.target.value}),
br(),
label('Hint:'),
input({value:hint, oninput:e=>hint.val=e.target.value}),
button({onclick:()=>click_get_hint()},'Get'),
button({onclick:()=>click_apply_hint()},'Apply'),
)
};
const CertsEL = () =>{
return div({id:'crets'},
label('Crets'),
)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment