Commit c81c95d2 authored by Bob Hageman's avatar Bob Hageman

removed unused dataflowtest folder

parent 93559b1f
# Schluss - Volksbank - Duo
Proof of concept dataflow example
## Requirements
- NPM
## Install
> npm install
## Run
The example application is made of two components:
- an endpoints module that launches the different webservices
- an example flow
From a terminal window, first launch the endpoints:
> node endpoints.js
Then launch the example flow in another terminal window:
> node example.js
Now, sit back, relax and watch the flow go:)
-----BEGIN CERTIFICATE-----
MIIDdjCCAl6gAwIBAgIJAMl0kh+jhjASMA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNV
BAYTAk5MMQswCQYDVQQIDAJaSDERMA8GA1UEBwwISGlsbGVnb20xDTALBgNVBAoM
BE15Ym8xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0xODA4MjYyMDA4MjBaFw0xOTA4
MjYyMDA4MjBaMFAxCzAJBgNVBAYTAk5MMQswCQYDVQQIDAJaSDERMA8GA1UEBwwI
SGlsbGVnb20xDTALBgNVBAoMBE15Ym8xEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALY+XeP1cCSGY6VTTz3nNvVSnEFx
eawHNc8D/H0cNsYi9e92dWevB4vtErymPOo6C1yG0ne+an5N2rb5zL1G+1xQ82Ym
8NJLofp3DooJfkkjmrf+s2ghBMXTNDSKTKsHyCewCMxgLU2t75sQwshQ5jSZXbWQ
MzYly5zZtkIFnbvp7cW2fXM111ctvnRS2EXr26hKY3BILdvP5+yWWwSByfYTr2t/
aJ6xzzIAQu3cYrTfeN2iNYV0epLp9UjpKqnoZ3CMuZ0tIpkOdyqtkAbx06VuQkLc
DGm1sXsdLD6NSVLFWUpfA5O7dn5rcAdBEY7XCZqgN8iwBIYvtKx79+M0V8sCAwEA
AaNTMFEwHQYDVR0OBBYEFOfue9zqOuTKUV6EDBxwI+ftA5m7MB8GA1UdIwQYMBaA
FOfue9zqOuTKUV6EDBxwI+ftA5m7MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
AQELBQADggEBAA0TLcGNcGotunmwxWBhTuyLfoNeKSqKhGcG4P5DQy0eSzGJwxP1
ypFb105a2v/YyzdPu/e1dJzJ1/iiJECLvGkvbOn95we79gQHUGNFlMiLjPgOybbS
Kg2HTrc4syiojvkJtLfTPECxs/nKlb2Tw5DbEFyXIFRmBeXbH0VeE6Kf5xxEozH6
0Hs92R95Q2UDBIxZX+89vZMBMpkCsRJzIVNMOd7fM/OIiTVpSdZfrNYt2UzCHDCU
pkANyFVNveXLtbkiNNn4eQprO4OM8LGSam+8+a77G17a8r+dV/eqYggyGOSU5LP6
Btdqf/we1xGL484+AYdMGALWVuuELjckmx8=
-----END CERTIFICATE-----
//"use strict";
// NPM-Free Server by The Jared Wilcurt
// All you need to run this is an installed copy of Node.JS
// Put this next to the files you want to serve and run: node server.js
// Require in some of the native stuff that comes with Node
var https = require('https');
var url = require('url');
var path = require('path');
var fs = require('fs');
// Port number to use
var port = process.argv[2] || 8181;
// Colors for CLI output
var WHT = '\033[39m';
var RED = '\033[91m';
var GRN = '\033[32m';
var options = {
key: fs.readFileSync('server.key'),
cert: fs.readFileSync('server.crt')
};
function handleRequest(request, response) {
// The requested URL, like http://localhost:8000/file.html => /file.html
var uri = '/src/' + url.parse(request.url).pathname;
// get the /file.html from above and then find it from the current folder
var filename = path.join(process.cwd(), uri);
// Setting up MIME-Type (YOU MAY NEED TO ADD MORE HERE) <--------
var contentTypesByExtension = {
'.html': 'text/html',
'.css': 'text/css',
'.js': 'text/javascript',
'.json': 'text/json',
'.svg': 'image/svg+xml',
'.jpg' : 'image/jpeg',
'.png' : 'image/png'
};
// Check if the requested file exists
fs.exists(filename, function (exists) {
// If it doesn't
if (!exists) {
// Output a red error pointing to failed request
console.log(RED + 'FAIL: ' + filename);
// Redirect the browser to the 404 page
filename = path.join(process.cwd(), '/404.html');
// If the requested URL is a folder, like http://localhost:8000/catpics
} else if (fs.statSync(filename).isDirectory()) {
// Output a green line to the console explaining what folder was requested
console.log(GRN + 'FLDR: ' + WHT + filename);
// redirect the user to the index.html in the requested folder
filename += '/index.html';
}
// Assuming the file exists, read it
fs.readFile(filename, 'binary', function (err, file) {
// Output a green line to console explaining the file that will be loaded in the browser
console.log(GRN + 'FILE: ' + WHT + filename);
// If there was an error trying to read the file
if (err) {
// Put the error in the browser
response.writeHead(500, {'Content-Type': 'text/plain'});
response.write(err + '\n');
response.end();
return;
}
// Otherwise, declare a headers object and a var for the MIME-Type
var headers = {};
var contentType = contentTypesByExtension[path.extname(filename)];
// If the requested file has a matching MIME-Type
if (contentType) {
// Set it in the headers
headers['Content-Type'] = contentType;
}
// Output the read file to the browser for it to load
response.writeHead(200, headers);
response.write(file, 'binary');
response.end();
});
});
}
// Create the server
https.createServer(options, handleRequest).listen(parseInt(port, 10));
// Message to display when server is started
console.log(WHT + 'Static file server running at\n => https://localhost:' + port + '/\nCTRL + C to shutdown');
\ No newline at end of file
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC2Pl3j9XAkhmOl
U0895zb1UpxBcXmsBzXPA/x9HDbGIvXvdnVnrweL7RK8pjzqOgtchtJ3vmp+Tdq2
+cy9RvtcUPNmJvDSS6H6dw6KCX5JI5q3/rNoIQTF0zQ0ikyrB8gnsAjMYC1Nre+b
EMLIUOY0mV21kDM2Jcuc2bZCBZ276e3Ftn1zNddXLb50UthF69uoSmNwSC3bz+fs
llsEgcn2E69rf2iesc8yAELt3GK033jdojWFdHqS6fVI6Sqp6GdwjLmdLSKZDncq
rZAG8dOlbkJC3AxptbF7HSw+jUlSxVlKXwOTu3Z+a3AHQRGO1wmaoDfIsASGL7Ss
e/fjNFfLAgMBAAECggEAYvINi/zv/ASzCUnoFhX48sz9ZVK02r+3aUQiy9KLspu8
p1zLdZXEJSZ8K8yd+hW1oXDZyIWr0BN5EisiDAoD4yVYYTf3PFYwBYqqbCunUxJv
qEIzKe/zZWy8RWJpKdq5w0KCJGR7dFdhZfF9r8CsnBZAmJlIFLgEio5xs/rUnvcC
t3+1wMIGT16d7TiKqSmnmATzzlD4xkyE1erI3o0/oR6xj+7GMqVutOEpDWnEcEAs
NSQcx3haIz/heU17ZTeGDZgHv7vzaMcjvGXNqO0rbrS1HWJEX1BX2LyIKgj2V6lf
E75nD5G1sjVIPRX/jn1QpJBAuCkcjF4TzHbiWmiK0QKBgQDcbsgkxrcnfTBwaQbB
GHGx1fleCDnIU0Bou7M8TKk4RdRuosLyiYYChQxEFkK0HZFgPfSSlwRyfxXoeEwv
ClceSCroKaIVK1QLgU7W4s3AowSeaXK5dYO86tXZylUzt0K/4CCZkhSdu9DrhNU7
42wsl9CrYdt0Jpmq3Wdw/lBntQKBgQDTpiQcNOSDJfkB7Qh9j0O80zC36TV/tntb
qSB8FKf181Ay4SqyXRdqHv0/j6Xe7K/PhEOsmqBPeuJkF4RM3Dnnoih7Rokdtkob
vyxRLFnqmux/YtkaE3U7OL7rYR3K3W35XoUwcxAJq4Qf6UYztuwvqfqp9/2j6vTR
xejHD6JxfwKBgQC/QErcRaERXPfS//zBOlEix5C1OhPQMBMZC4mmDqlfTo7SctsL
jbA8rW0IAfxbw6+nPfnd2bMdGBBNA1quEZ2mg1ze04hyL4aa+NULcfqsYYQXYUwN
ht0G4wUqEfe8iAsc6Pu/4lOKyzKntTdA37+yLQH6QEwkSX1YFwKxsaTXZQKBgETa
8zp99q24B9eZjr6Sgj4HEv1yEGaZLm62igv0CGSaoMe8u1BFut1acZdhG1x38gZ4
CDA6KddRqh9YC0GaD/iMp9DbNLaG3HtEaZ2K6UHK3w/eT7UNCYGXx3z6HmAmQ6Xy
GzCU7m3G7/gVwzIF27bx/MuZE1plkPpCAaXpLzbvAoGAMxOvT2XcX2dhrUmdFWhi
IC58dQ29/YaxTRuabRJtCmdZgxyEdtKfoorfY+RweSdKeh9qWUHI/AJGmBmeybBc
1rnUh7GaHG5+I5Yu0W69TMCbFPxcD2bBl6Z7QLHi+Ct05hfpip+7jnS1pI+K2EG+
+lVhBGauZNfVHoyylihGx94=
-----END PRIVATE KEY-----
var fs = require('fs');
// disable self signed cert blocking - only for local use!
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
module.exports = {
user : {
name : 'John Doe',
email : 'john@doe.com',
pincode : 1234
},
debug : {
enableSleep : true,
extraSlowwww : true
},
serverkeys : {
key: fs.readFileSync('./_keys/server.key'),
cert: fs.readFileSync('./_keys/server.crt')
},
// endpoints
staatdernederlanden :
{
port : 8080,
url : 'https://localhost:8080/'
},
volksbank :
{
port : 8081,
url : 'https://localhost:8081/'
},
duo :
{
port : 8082,
url : 'https://localhost:8082/'
},
ipfs :
{
port : 8083,
url : 'https://localhost:8083/'
}
};
\ No newline at end of file
# Ter discussie:
- Gedachten bij json bedachte structuur (import / export) voor data exchange via schluss?
- Voor koppelende partijen: qr code embedden mbhv javascript (Google Analytics / Matomo methode)
- Hoe zonder centrale keyserver voor keyexchange (via e-mail adres als identifier) goed gebruik maken van (Open)PGP?
- Data opslaan in IPFS = 1x encrypted met eigen key en 1x met public key Volksbank? Of Exchange middels request aan Schluss API? Maar dan is er middleware bij Schluss nodig? -> Tegen decentraal principe in
- Welke methode van ophalen data bij DUO? Is hier al meer bekend over? Hoorde iets van XML? Maar is dit een 'los' XML document dat je gewoon download? Hope not - zou mooi zijn als dit via een api/url doorgestuurd kan worden aan de vragende dienst
Mijn aanname:
-bij benaderen DUO pagina in url redirect parameter meegeven
-vervolgens bij klikken op Blue button wordt het XML document in encoded string doorgestuurd aan de redirect url
-de DUO pagina wordt hierbij verlaten
- Welk format data exchange tussen Schluss en Volksbank?
-- Via de URL doorsturen (omdat we toch al in zo'n flow zitten) = instant
-- Of IPFS hash doorsturen in URL en dan dat Volksbank manual IPFS node uitleest in apart proces?
- Voorkeur heeft om data voor een bepaalde tijd beschikbaar te stellen, dus Volksbank krijgt mogelijkheid tot vaker ophalen. Via API of direct uit IPFS (=geen controle over ontzegging voorsalsnog)?
\ No newline at end of file
// Duo.nl
var schlussapp = require('../schluss.app/app');
var shared = require('../shared');
module.exports = {
// when browser redirects to the duo.nl website the program continues here.
redirectTo : async function(params)
{
try
{
shared.message('I\'ve arrived at the duo.nl login page\n');
shared.wait(1);
// login at / with digid
shared.message('I log in with my Digid credentials');
shared.wait(1);
shared.status('ok');
shared.wait(1);
shared.message('I now see my study dept: € 20.000,00');
shared.wait(1);
shared.message('I click on the Blue button, to export my study debt in (JSON format)...');
shared.wait(1);
shared.status('ok');
shared.message('Duo asks me if it\'s okay to share this info with Schluss and redirect back...');
shared.wait(1);
shared.status('ok');
let redirectParams = {
token : params.token, // identifier so schluss.app knows what we're getting back
format : 'json', // what kind of payload?
payload : '{"name":"studieschuld","value":"20000"}' // xml / json (?) document with returned data
};
// redirect back to schluss.app
schlussapp.redirectBack(redirectParams);
}
catch(e)
{
console.log(e);
}
}
};
{
"appname":"duo.nl",
"version":"1.0",
"name":"Duo",
"description":"",
"website":"https://localhost:8082",
"logourl":"https://localhost:8082/media/logo.svg",
"export":[
{"name":"studieschuld","label":"Studieschuld","description":"Overzicht van je huidige studieschuld"}
],
"endpoints" : {
"connect" : "https://localhost:8082/connect",
}
}
\ No newline at end of file
var express = require('express');
var https = require('https');
var http = require('http');
var url = require('url');
var path = require('path');
var fs = require('fs');
var config = require('./config');
let staatdernederlanden = require('./staatdernederlanden.nl/app');
var volksbank = require('./volksbank.nl/app');
var duo = require('./duo.nl/app');
var ipfs = require('./ipfs.io/app');
var endpointNr = 0;
// start all api services
console.log('\nStart api services...\n');
// staatdernederlanden.nl
https.createServer(config.serverkeys, staatdernederlanden).listen(config.staatdernederlanden.port, function(){
console.log('- staatdernederlanden.nl ['+ config.staatdernederlanden.url +']');
goOn();
});
// Volksbank.nl
https.createServer(config.serverkeys, volksbank).listen(config.volksbank.port, function(){
console.log('- volksbank.nl ['+ config.volksbank.url +']');
goOn();
});
// duo.nl
/*
https.createServer(config.serverkeys, duo).listen(config.duo.port, function(){
console.log('- duo.nl ['+ config.duo.url +']');
goOn();
});
*/
// ipfs.io
https.createServer(config.serverkeys, ipfs).listen(config.ipfs.port, function(){
console.log('- ipfs.io ['+ config.ipfs.url +']');
goOn();
});
function goOn()
{
endpointNr++;
if (endpointNr < 3)
return;
console.log('\nReady! Now you can run the example.js.\n\nEndpoint messages:\n');
}
\ No newline at end of file
var request = require('request-promise-native');
var config = require('./config');
var schlussapp = require('./schluss.app/app');
var shared = require('./shared');
async function IAmAtVolksbankAndWantAMortgage()
{
try {
shared.message('\nHi, I\'m browser, controlled by someone who\'s totally analogous.\nYou see me at the Volksbank while you\'re in the process of getting an offer for a mortgage. I want to give Volksbank insight in my study debt, let\'s do it!\n');
shared.wait(5);
shared.message('I\'ve got a keypair from staatdernederlanden.nl, time to load it...');
let keypairResponse = await request.get(config.staatdernederlanden.url + 'getkeys');
if (keypairResponse == undefined)
throw 'invalid keypair';
const keypair = JSON.parse(keypairResponse);
shared.status('ok');
shared.wait(1);
shared.message('I see a QR code, let\'s scan it with my phone...');
let vbResponse = await request.get(config.volksbank.url + 'qr');
if (vbResponse == undefined)
throw 'invalid qr redirect';
const vbSettings = JSON.parse(vbResponse);
shared.wait(1);
shared.status('ok');
shared.wait(2);
shared.message('My phone wants to redirect me, okay, totally fine!');
shared.wait(1);
shared.message('- redirecting...');
shared.status('ok');
// ok, now redirect my browser to the Schluss app
// flow continues in: /schluss.app/app.js
schlussapp.redirectTo(vbSettings);
}
catch(e) {
shared.message(e);
}
}
// HI, I am a browser, controlled by someone who's becoming a customer at Volksbank
// Run self: Me at Volksbank
IAmAtVolksbankAndWantAMortgage();
\ No newline at end of file
// IPFS
var express = require('express');
var bodyParser = require('body-parser');
var shared = require('../shared');
var fs = require('fs');
var app = express();
app.use(bodyParser.json()); // support json encoded bodies
app.use(bodyParser.urlencoded({ extended: true })); // support encoded bodies
app.get('/', function(req,res)
{
res.send('ipfs.io API');
});
app.post('/add', function (req, res) {
console.log('- [post] ipfs.io/add: store a document');
let id = shared.uuidv4();
let filename = __dirname + '/db/' + id;
//console.log(req.body);
fs.writeFileSync(filename, JSON.stringify(req.body) , 'utf-8');
console.log('- stored with id: ' + id);
let response = { id : id };
res.setHeader('Content-Type', 'application/json');
res.send(JSON.stringify(response));
});
// to be able to serve static files (like config.js)
app.use(express.static(__dirname));
module.exports = app;
\ No newline at end of file
# Ignore everything
*
# But not these files...
!.gitignore
!*.txt
\ No newline at end of file
This diff is collapsed.
{
"name": "Dataflowtest.app",
"title": "Datflow test",
"version": "0.0.1",
"repository": {
"type": "git",
"url": "https://gitlab.com/schluss/schluss.app.git"
},
"author": "Bob Hageman <bob@schluss.org>",
"license": "UNKNOWN",
"bugs": {
"url": "https://gitlab.com/schluss/schluss.app/issues"
},
"homepage": "https://www.schluss.org",
"private": true,
"dependencies": {
"body-parser": "^1.18.3",
"express": "^4.16.3",
"node-rsa": "^1.0.1",
"openpgp": "^4.0.2",
"request": "^2.88.0",
"request-promise-native": "^1.0.5",
"system-sleep": "^1.3.6"
},
"devDependencies": {}
}
// schluss.app
var request = require('request-promise-native');
var config = require('../config');
var shared = require('../shared');
var fs = require('fs');
module.exports = {
// when browser redirects to the schluss.app, the program continues here: in the schluss.app domain (of course runned/hosted locally at the users browser!)
redirectTo : async function(params)
{
try
{
shared.message('I\'ve arrived at the schluss.app landing / onboarding web-app\n');
shared.wait(1);
// create a new locker (fake for this demo)
shared.message('I\'m not a Schluss user yet, creating a new locker...');
let lockerPath = __dirname + '/db/' + config.user.email.replace('@','-') + '.json';
// save the 'users session' and 'connection + share request'
fs.writeFileSync(lockerPath, JSON.stringify(params) , 'utf-8');
shared.wait(2);
shared.status('ok');
shared.wait(2);
// get volksbank config.json file
let vbconfigResponse = await request.get(params.settingsurl);
if (vbconfigResponse == undefined)
throw 'invalid config.json';
const vbconfig = JSON.parse(vbconfigResponse);
// get the scope details
let scope = vbconfig.import.find( function(item) { return item.scope == params.scope } );
// use params to initiate a connection request
shared.message('The app asks me to go to Duo, where I need to login to retrieve my study dept');
shared.wait(1);
shared.message('- redirecting...');
shared.status('ok');
let redirectParams = {
redirectUrl : 'schluss.app/#?...', // dummy for the sake of this demo (at duo we'll call the js function redirectBack instead of using the url)
request : 'studieschuld', // the requested datafields
returnMethod : 'url', // return the data in a base64 encoded querystring, future: make it possible to choose url(=direct/in flow) / api(=async) / etc
token : shared.uuidv4() // a token for the session between duo and Schluss.app - todo: find out where this must came from: schluss.app or duo?
};
// redirect to duo, send extra parameters
// flow continues in: /duo.nl/app.js
// the real life url should look like (properly base64 encoded of course):
// https://duo.nl/login?redirect=https://schluss.app/#returnimport?token=[token]&return=
duoapp.redirectTo(redirectParams);
}
catch(e)
{
console.log(e);
}
//console.log(vbconfig);
},
// redirected back from duo, we now have the studieschuld in urlparam
redirectBack : async function(params)
{
try {
let payload = JSON.parse(params.payload);
shared.message('Welcome back to Schluss.app, opening your locker...');
shared.wait(1);
shared.status('ok');
shared.message('Bingo! Got your study debt from Duo: ' + payload.value);
shared.wait(2);
shared.message('Encrypt and store study debt in IPFS...');
// encrypt datapackage (study dept) with public key of volksbank(?) and store in ipfs
// todo: public key volksbank? but then it is only decryptable by volksbank? or store for yourself and send via url/api to volksbank?
var options = {
method: 'POST',
uri: config.ipfs.url + 'add',
body: {
metadata: 'here',
payload : payload
},
json: true // stringifies body to JSON
};
let ipfsResponse = await request(options);
shared.wait(2);
shared.status('ok');
shared.message('Todo: connect back to volksbank... debug:');
console.log(ipfsResponse);
// lets go on, connect back to volksbank
return '';
}
catch(e)
{
console.log(e);
}
}
};
// require here, because else there's a problem with circular dependencies
// quick and dirty, but it works for this test
// explanation: http://blog.cloudmineinc.com/managing-cyclic-dependencies-in-node.js?hsFormKey=ae1b2c3916d0a2be7aafb5d841ce24c0
var duoapp = require('../duo.nl/app');
\ No newline at end of file
# Ignore everything
*
# But not these files...
!.gitignore
!*.txt
\ No newline at end of file
var sleep = require('system-sleep');
var config = require('./config');
module.exports = {
// helper functions
message : function(text)
{
process.stdout.write('\n ' + text);
},
status : function(type, text)
{
// Colors for CLI output
var WHT = '\033[39m';
var RED = '\033[91m';
var GRN = '\033[32m';
text == undefined ? '' : text;
switch(type)
{
case 'ok' : process.stdout.write(GRN + '[ok]' + WHT);
break;
case 'error' : process.stdout.write(RED + '[error]' + WHT);
break;
}
console.log('');
},
wait : function(seconds)
{
if (config.debug.extraSlowwww)
seconds *= 2;
if (config.debug.enableSleep)
sleep(seconds * 1000);
},
// simple uuid v4 generation, do not use in production, math.random is not really random!
uuidv4 : function () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
};
\ No newline at end of file
// Staatdernederlanden.nl
var express = require('express');
var app = express();
var openpgp = require('openpgp');
var fs = require('fs');
var config = require('../config');
const rsa = require('node-rsa');
app.get('/', function(req,res)
{
res.send('staatdernederlanden.nl API');
});
// generate and return a json encoded rsa key pair
app.get('/getkeys', async function(req,res)
{
console.log('- [get] staatdernederlanden.nl/getkeys: get the users\' RSA key