Skip to content

Instantly share code, notes, and snippets.

@antoniogarrote
Created October 17, 2011 19:28
Show Gist options
  • Save antoniogarrote/1293526 to your computer and use it in GitHub Desktop.
Save antoniogarrote/1293526 to your computer and use it in GitHub Desktop.
webid nodejs
var https = require('https');
var http = require('http');
var util = require('util');
var fs = require('fs');
var url = require('url');
var raptor = require('./raptor.js');
var rdfstore = require('./rdfstore.js');
var port = 8081;
var options = { key: fs.readFileSync('./ssl/privatekey.pem'),
cert: fs.readFileSync('./ssl/certificate.pem'),
requestCert: true, };
var profilePage = function(profile) {
var html = "<html><head><title>Success: "+profile.toArray()[0].subject.valueOf()+"</title></head><body>"
var depiction = profile.filter(function(t){ return t.predicate.equals("http://xmlns.com/foaf/0.1/depiction") }).toArray();
if(depiction.length === 1) {
depiction = depiction[0].object.valueOf();
}
var familyName = profile.filter(function(t){ return t.predicate.equals("http://xmlns.com/foaf/0.1/family_name") }).toArray();
if(familyName.length === 1) {
familyName = familyName[0].object.valueOf();
}
var givenName = profile.filter(function(t){ return t.predicate.equals("http://xmlns.com/foaf/0.1/givenname") }).toArray();
if(givenName.length === 1) {
givenName = givenName[0].object.valueOf();
}
var nick = profile.filter(function(t){ return t.predicate.equals("http://xmlns.com/foaf/0.1/nick") }).toArray();
if(nick.length === 1) {
nick = nick[0].object.valueOf();
}
var homepage = profile.filter(function(t){ return t.predicate.equals("http://xmlns.com/foaf/0.1/homepage") }).toArray();
if(homepage.length === 1) {
homepage = homepage[0].object.valueOf();
}
html = html + "<p><img src='"+depiction+"'></img>";
html = html + "<a href='"+homepage+"'>"+givenName+" "+familyName+" ("+nick+")</a></p>";
html = html + "</body></html>";
return html
};
console.log("trying to create server at "+port);
https.createServer(options,function (req, res) {
var certificate = req.connection.getPeerCertificate();
if(certificate) {
var verifAgent = new VerificationAgent(certificate);
verifAgent.verify(function(err, profileGraph){
if(err) {
res.writeHead(400,{"Content-Type":"text/plain"});
res.write(profileGraph);
} else {
res.writeHead(200,{"Content-Type":"text/html"});
res.write(profilePage(profileGraph));
}
res.end();
});
} else {
res.writeHead(400,{"Content-Type":"text/plain"});
res.write("not auth");
res.end();
}
}).listen(port);
console.log("server running at "+port);
VerificationAgent = function(certificate){
this.subjectAltName = certificate.subjectaltname;
this.modulus = certificate.modulus;
this.exponent = certificate.exponent;
this.uris = this.subjectAltName.split(",")
for(var i=0; i<this.uris.length; i++) {
this.uris[i] = this.uris[i].split("URI:")[1];
}
};
VerificationAgent.prototype.verify = function(callback) {
this._verify(this.uris,callback);
};
VerificationAgent.prototype._verify = function(uris, callback) {
if(uris.length === 0) {
callback(true,"NotVerified");
} else {
var that = this;
var parsedUrl = url.parse(uris[0]);
var options = {host: parsedUrl.host,
path: parsedUrl.pathname,
method: 'GET',
headers: {"Accept": "application/rdf+xml,application/xhtml+xml,text/html"}};
var req = http.request(options,function(response){
if(response.statusCode==200) {
var res = "";
response.on('data', function(chunk){
res = res+chunk;
});
response.on('end', function(){
var contentType = (response.headers['content-type'] || response.headers['Content-Type'])
if(contentType) {
that._verifyWebId(uris[0], res, contentType, callback);
} else {
callback(true,"missingResponseContentType");
}
});
} else {
callback(true, "badRemoteResponse");
}
});
req.on('error', function(error) {
uris.shift();
that._verify(uris, callback);
});
req.end();
}
};
VerificationAgent.prototype._verifyWebId = function(webidUri, data, mediaTypeHeader, callback) {
var that = this;
var mediaType = null;
if(mediaTypeHeader === "application/rdf+xml") {
mediaType = 'rdfxml';
} else {
mediaType = 'rdfa';
}
var parser = raptor.newParser(mediaType);
var statements = "";
var nextStatement = "";
parser.on('statement', function(statement) {
nextStatement = "<"+statement.subject.value+"><"+statement.predicate.value+">";
if(statement.object.type === "uri") {
nextStatement = nextStatement + "<"+statement.object.value+">.";
} else {
nextStatement = nextStatement + "\""+statement.object.value+"\".";
}
statements = statements+nextStatement;
});
parser.on('end', function(){
rdfstore.create(function(store){
store.load("text/turtle",statements,function(success, results) {
store.execute("PREFIX cert: <http://www.w3.org/ns/auth/cert#>\
PREFIX rsa: <http://www.w3.org/ns/auth/rsa#>\
SELECT ?m ?e ?webid\
WHERE {\
?cert cert:identity ?webid ;\
rsa:modulus ?m ;\
rsa:public_exponent ?e .\
}", function(success, results) {
if(success) {
var modulus = null;
var exponent = null;
for(var i=0; i<results.length; i++) {
if(results[i].webid && results[i].webid.value===webidUri) {
modulus = results[i].m;
exponent = results[i].e;
}
}
if(modulus!=null && exponent!=null) {
that._resolveModulusValue(store, modulus, function(modulus){
that._resolveExponentValue(store, exponent, function(exponent) {
if((""+that.modulus==""+modulus) &&
(""+that.exponent == ""+exponent)) {
store.node(webidUri, function(success, graph) {
callback(false, graph);
});
} else {
callback(true, "notMatchingCertificate");
}
});
});
} else {
callback(true, "certficateDataNotFound");
}
} else {
callback(true, "certficateDataNotFound");
}
});
});
});
});
parser.parseStart(webidUri);
parser.parseBuffer(new Buffer(data));
parser.parseBuffer();
};
VerificationAgent.prototype._resolveModulusValue = function(store, modulus, cb) {
if(modulus.token === 'uri') {
store.execute("SELECT ?v { <"+modulus.value+"><http://www.w3.org/ns/auth/cert#hex>?v }", function(success, results){
if(results.length == 1) {
cb(results[0].v.value);
} else {
store.execute("SELECT ?v { <"+modulus.value+"><http://www.w3.org/ns/auth/cert#decimal>?v }", function(success, results){
cb(parseInt(results[0].v.value).toString(16));
})
}
});
} else {
if(modulus.type == "http://www.w3.org/ns/auth/cert#decimal") {
cb(parseInt(modulus.value).toString(16));
} else {
cb(modulus.value);
}
}
};
VerificationAgent.prototype._resolveExponentValue = function(store, exponent, cb) {
if(exponent.token === 'uri') {
store.execute("SELECT ?v { <"+exponent.value+"><http://www.w3.org/ns/auth/cert#hex>?v }", function(success, results){
if(results.length == 1) {
cb(results[0].v.value);
} else {
store.execute("SELECT ?v { <"+exponent.value+"><http://www.w3.org/ns/auth/cert#decimal>?v }", function(success, results){
cb(parseInt(results[0].v.value).toString(16));
});
}
});
} else {
if(exponent.type == "http://www.w3.org/ns/auth/cert#decimal") {
cb(parseInt(exponent.value).toString(16));
} else {
cb(exponent.value);
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment