pax_global_header00006660000000000000000000000064121715271710014516gustar00rootroot0000000000000052 comment=cb888bffb83bf7ebe79df4ff24bc6cedf8c9d63f webfinger-0.4.2/000077500000000000000000000000001217152717100134715ustar00rootroot00000000000000webfinger-0.4.2/.gitignore000066400000000000000000000001541217152717100154610ustar00rootroot00000000000000lib-cov *.seed *.log *.csv *.dat *.out *.pid *.gz pids logs results node_modules npm-debug.log config.js webfinger-0.4.2/.travis.yml000066400000000000000000000002041217152717100155760ustar00rootroot00000000000000language: node_js node_js: - "0.8" - "0.10" script: "sudo /usr/local/bin/node node_modules/.bin/vows -i --spec test/*-test.js" webfinger-0.4.2/LICENSE000066400000000000000000000261361217152717100145060ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. webfinger-0.4.2/README.md000066400000000000000000000103551217152717100147540ustar00rootroot00000000000000# Webfinger Webfinger and host-meta client library for Node.js. It supports: * XRD documents * JRD documents * host-meta * host-meta.json * http and https * RFC 6415 and the upcoming Webfinger RFC (up to draft 09) ## License Copyright 2012,2013 E14N https://e14n.com/ Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ## API ### webfinger(address, callback) Gets link data for the address `address` and returns it to function `callback`. The `address` argument can be any kind of URL that node.js recognizes; acct: and http: and https: URLs are the most likely to work. `callback` should take two arguments: `err` for an error, and `jrd` for a JRD representation of the Webfinger data. Note that the data is returned in JRD format even if it's in XRD format on the server. This method will first try the `/.well-known/webfinger` endpoint; if that doesn't work it will fall back to RFC 6415 discovery. ### webfinger(address, rel, callback) As above, but passes the `rel` parameter to the `/.well-known/webfinger` endpoint if it's truthy. This is mostly advisory. Some servers will send all links back anyways; others don't support the webfinger endpoint, so when we fallback to RFC 6415 everything is returned. Even if you pass a `rel` argument, you should still filter the results. (But future versions of this library may do it for you.) ### webfinger(address, rel, options, callback) As above, but you can use the `options` object to control behaviour. Currently, the options are: * `httpsOnly`: boolean flag, default `false` for whether to only use HTTPS for communicating with the server. When this is set, it won't use Webfinger, host-meta or LRDD endpoints that aren't HTTPS, and won't follow redirect requests to HTTP endpoints. * `webfingerOnly`: boolean flag, default `false` for whether to only use the .well-known/webfinger endpoint. When this is set, it won't use host-meta and LRDD endpoints as a fallback. ### lrdd(address, callback) Explicitly use Host Metadata + LRDD lookup per RFC 6415 and avoid the /.well-known/webfinger endpoint. Use this if you know a host only supports LRDD. ### lrdd(address, options, callback) As above, but with fine control of options. Options include: * `httpsOnly`: boolean flag, default `false` for whether to only use HTTPS for communicating with the server. When this is set, it won't use Webfinger, host-meta or LRDD endpoints that aren't HTTPS, and won't follow redirect requests to HTTP endpoints. ### hostmeta(address, callback) Gets link data for the host at `address` and returns it to function `callback`. `callback` works just like with `webfinger()`. ### hostmeta(address, options, callback) As above, but you can use the `options` object to control behaviour. Currently, the options are: * `httpsOnly`: boolean flag, default `false`, for whether to only use HTTPS for communicating with the server. When this is set, it won't use host-meta or host-meta.json endpoints that aren't HTTPS, and won't follow redirect requests to HTTP endpoints. ### discover(address, callback) Gets link data for `address` and returns it to function `callback`. If you've got an address and you don't want to bother figuring out if it's a webfinger or a hostname, call this and we'll do it for you. `callback` works just like with `webfinger()`. ## Testing The tests set up servers that listen on ports 80 and 443. On most Unix-like systems, you have to be root to listen on ports below 1024 or whatever. So, to run the unit tests, you have to go: sudo npm test It's probably not a good idea to sudo any script without thinking about it pretty hard. I suggest that if you're doing development, you do it in a virtual machine so you're not sudo'ing dangerous stuff on your main computer. # Bugs Bugs welcome, see: https://github.com/e14n/webfinger/issues webfinger-0.4.2/lib/000077500000000000000000000000001217152717100142375ustar00rootroot00000000000000webfinger-0.4.2/lib/webfinger.js000066400000000000000000000415101217152717100165460ustar00rootroot00000000000000// index.js // // main module for Webfinger // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var Step = require("step"), dns = require("dns"), http = require("http"), https = require("https"), xml2js = require("xml2js"), url = require("url"), querystring = require("querystring"); var JSONTYPE = "application/json", XRDTYPE = "application/xrd+xml"; var xrd2jrd = function(str, callback) { var getProperty = function(obj, Property) { var k, v; if (Property.hasOwnProperty("@")) { if (Property["@"].hasOwnProperty("type")) { k = Property["@"]["type"]; } if (Property["@"].hasOwnProperty("xsi:nil") && Property["@"]["xsi:nil"] == "true") { obj[k] = null; } else if (Property.hasOwnProperty("#")) { obj[k] = Property["#"]; } else { // TODO: log this } } }, getTitle = function(obj, Title) { var k = "default"; if (typeof(Title) == "string") { obj[k] = Title; } else { if (Title.hasOwnProperty("@")) { if (Title["@"].hasOwnProperty("xml:lang")) { k = Title["@"]["xml:lang"]; } } if (Title.hasOwnProperty("#")) { obj[k] = Title["#"]; } } }, getLink = function(Link) { var prop, i, l, k, v, Property, Title; l = {}; if (Link.hasOwnProperty("@")) { for (prop in Link["@"]) { if (Link["@"].hasOwnProperty(prop)) { l[prop] = Link["@"][prop]; } } } if (Link.hasOwnProperty("Property")) { // groan l.properties = {}; if (Array.isArray(Link.Property)) { for (i = 0; i < Link.Property.length; i++) { getProperty(l.properties, Link.Property[i]); } } else { getProperty(l.properties, Link.Property); } } if (Link.hasOwnProperty("Title")) { l.titles = {}; if (Array.isArray(Link.Title)) { for (i = 0; i < Link.Title.length; i++) { getTitle(l.titles, Link.Title[i]); } } else { getTitle(l.titles, Link.Title); } } return l; }; Step( function() { var parser = new xml2js.Parser(); parser.parseString(str, this); }, function(err, doc) { var Link, jrd = {}, i, prop, l; if (err) { callback(err, null); } else { // XXX: Booooooo! This is bletcherous. if (doc.hasOwnProperty("Subject")) { if (Array.isArray(doc.Subject)) { jrd.subject = doc.Subject[0]; } else { jrd.subject = doc.Subject; } } if (doc.hasOwnProperty("Expires")) { if (Array.isArray(doc.Expires)) { jrd.expires = doc.Expires[0]; } else { jrd.expires = doc.Expires; } } if (doc.hasOwnProperty("Alias")) { if (Array.isArray(doc.Alias)) { jrd.aliases = doc.Alias; } else { jrd.aliases = [doc.Alias]; } } if (doc.hasOwnProperty("Property")) { jrd.properties = {}; if (Array.isArray(doc.Property)) { for (i = 0; i < doc.Property.length; i++) { getProperty(jrd.properties, doc.Property[i]); } } else { getProperty(jrd.properties, doc.Property); } } if (doc.hasOwnProperty("Link")) { Link = doc.Link; jrd.links = []; if (Array.isArray(Link)) { for (i = 0; i < Link.length; i++) { jrd.links.push(getLink(Link[i])); } } else { jrd.links.push(getLink(Link)); } } callback(null, jrd); } } ); }; var jrd = function(body, callback) { var result; try { result = JSON.parse(body); callback(null, result); } catch (err) { callback(err, null); } }; var request = function(module, options, parsers, callback) { var types = [], prop; for (prop in parsers) { if (parsers.hasOwnProperty(prop)) { types.push(prop); } } var req = module.request(options, function(res) { var body = ""; res.setEncoding('utf8'); res.on('data', function (chunk) { body = body + chunk; }); res.on("error", function(err) { callback(err, null); }); res.on("end", function() { var ct, matched, parser, newopts; if (res.statusCode > 300 && res.statusCode < 400 && res.headers.location) { newopts = url.parse(res.headers.location); // Don't redirect if it's not allowed if (options.httpsOnly && newopts.protocol != "https:") { callback(new Error("Refusing to redirect to non-HTTPS url: " + res.headers.location), null); return; } newopts.httpsOnly = options.httpsOnly; request(((newopts.protocol == "https:") ? https : http), newopts, parsers, callback); return; } else if (res.statusCode !== 200) { callback(new Error("Bad response code: " + res.statusCode + ":" + body), null); return; } if (!res.headers["content-type"]) { callback(new Error("No Content-Type header"), null); return; } ct = res.headers["content-type"]; matched = types.filter(function(type) { return (ct.substr(0, type.length) == type); }); if (matched.length == 0) { callback(new Error("Content-Type '"+ct+"' does not match any expected types: "+types.join(",")), null); return; } parser = parsers[matched]; parser(body, callback); }); }); req.on('error', function(err) { callback(err, null); }); req.end(); }; var httpHostMeta = function(address, callback) { var options = { hostname: address, port: 80, path: "/.well-known/host-meta", method: "GET", headers: { accept: "application/json, application/xrd+xml; q=0.5" } }; request(http, options, {"application/json": jrd, "application/xrd+xml": xrd2jrd}, callback); }; var httpHostMetaJSON = function(address, callback) { var options = { hostname: address, port: 80, path: "/.well-known/host-meta.json", method: "GET" }; request(http, options, {"application/json": jrd}, callback); }; var httpsHostMeta = function(address, httpsOnly, callback) { var options = { hostname: address, port: 443, path: "/.well-known/host-meta", method: "GET", headers: { accept: "application/json, application/xrd+xml; q=0.5" }, httpsOnly: httpsOnly }; request(https, options, {"application/json": jrd, "application/xrd+xml": xrd2jrd}, callback); }; var httpsHostMetaJSON = function(address, httpsOnly, callback) { var options = { hostname: address, port: 443, path: "/.well-known/host-meta.json", method: "GET", httpsOnly: httpsOnly }; request(https, options, {"application/json": jrd}, callback); }; var invalidHostname = function(hostname) { var examples = ["example.com", "example.org", "example.net"], tlds = ["example", "invalid"], parts; if (examples.indexOf(hostname.toLowerCase()) != -1) { return true; } parts = hostname.split("."); if (tlds.indexOf(parts[parts.length - 1]) != -1) { return true; } return false; }; var hostmeta = function(address, options, callback) { // options is optional if (!callback) { callback = options; options = {}; } if (invalidHostname(address)) { callback(new Error("Invalid hostname: " + address), null); return; } Step( function() { dns.lookup(address, this); }, function(err, address, family) { if (err) { callback(err, null); return; } else { httpsHostMetaJSON(address, options.httpsOnly, this); } }, function(err, jrd) { if (!err) { callback(null, jrd); } else if (err.code == 'ECONNREFUSED') { // Skip this test; no use trying to connect to HTTPS again this(err, null); } else { httpsHostMeta(address, options.httpsOnly, this); } }, function(err, jrd) { if (!err) { callback(null, jrd); } else if (options.httpsOnly) { callback(new Error("No HTTPS endpoint worked"), null); } else { httpHostMetaJSON(address, this); } }, function(err, jrd) { if (!err) { callback(null, jrd); } else if (err.code == 'ECONNREFUSED') { // Skip this test; no use trying to connect to HTTP again this(err, null); } else { httpHostMeta(address, this); } }, function(err, jrd) { if (!err) { callback(null, jrd); } else { callback(new Error("Unable to get host-meta or host-meta.json"), null); } } ); }; var httpsWebfinger = function(hostname, resource, rel, callback) { var params, qs, options; params = { resource: resource }; if (rel) { params.rel = rel; } qs = querystring.stringify(params), options = { hostname: hostname, port: 443, path: "/.well-known/webfinger?" + qs, method: "GET", httpsOnly: true }; request(https, options, {"application/json": jrd}, callback); }; var template = function(tmpl, address, parsers, httpsOnly, callback) { Step( function() { var getme = tmpl.replace("{uri}", encodeURIComponent(address)), options = url.parse(getme); options.httpsOnly = httpsOnly; request(((options.protocol == "https:") ? https : http), options, parsers, this); }, function(err, jrd) { var getme, options; if (!err) { callback(null, jrd); return; } else if (address.substr(0, 5) == "acct:") { // Retry with just the bare address getme = tmpl.replace("{uri}", encodeURIComponent(address.substr(5))), options = url.parse(getme); options.httpsOnly = httpsOnly; request(((options.protocol == "https:") ? https : http), options, parsers, this); } else { throw err; } }, function(err, jrd) { if (err) { callback(err, null); } else { callback(null, jrd); } } ); }; var lrdd = function(resource, options, callback) { var parsed, hostname; // Options parameter is optional if (!callback) { callback = options; options = {}; } // Prefix it with acct: if it looks like a bare webfinger if (resource.indexOf(":") === -1) { if (resource.indexOf("@") !== -1) { resource = "acct:" + resource; } } parsed = url.parse(resource); hostname = parsed.hostname; Step( function() { hostmeta(hostname, options, this); }, function(err, hm) { var lrdds, json, xrd; if (err) throw err; if (!hm.hasOwnProperty("links")) { throw new Error("No links in host-meta"); } // First, get the lrdd ones lrdds = hm.links.filter(function(link) { return (link.hasOwnProperty("rel") && link.rel == "lrdd" && link.hasOwnProperty("template") && (!options.httpsOnly || link.template.substr(0, 6) == "https:")); }); if (!lrdds || lrdds.length === 0) { throw new Error("No lrdd links with templates in host-meta"); } // Try JSON ones first json = lrdds.filter(function(link) { return (link.hasOwnProperty("type") && link.type == JSONTYPE); }); if (json && json.length > 0) { template(json[0].template, resource, {"application/json": jrd}, options.httpsOnly, this); return; } // Try explicitly XRD ones second xrd = lrdds.filter(function(link) { return (link.hasOwnProperty("type") && link.type == XRDTYPE); }); if (xrd && xrd.length > 0) { template(xrd[0].template, resource, {"application/xrd+xml": xrd2jrd}, options.httpsOnly, this); return; } // Try implicitly XRD ones third xrd = lrdds.filter(function(link) { return (!link.hasOwnProperty("type")); }); if (xrd && xrd.length > 0) { template(xrd[0].template, resource, {"application/xrd+xml": xrd2jrd}, options.httpsOnly, this); return; } // Otherwise, give up throw new Error("No lrdd links with templates and acceptable type in host-meta"); }, callback ); } var webfinger = function(resource, rel, options, callback) { var parsed, hostname; // Options parameter is optional if (!callback) { callback = options; options = {}; } // Rel parameter is optional if (!callback) { callback = rel; rel = null; } // Prefix it with acct: if it looks like a bare webfinger if (resource.indexOf(":") === -1) { if (resource.indexOf("@") !== -1) { resource = "acct:" + resource; } } parsed = url.parse(resource); hostname = parsed.hostname; if (invalidHostname(hostname)) { callback(new Error("Invalid hostname: " + hostname), null); return; } Step( function() { httpsWebfinger(hostname, resource, rel, this); }, function(err, jrd) { if (!err) { // It worked; return the jrd callback(null, jrd); return; } else if (resource.substr(0, 5) == "acct:") { // Retry with bare webfinger, no acct: httpsWebfinger(hostname, resource.substr(5), rel, this); } else { throw err; } }, function(err, jrd) { if (!err) { // It worked; return the jrd callback(null, jrd); return; } if (options.webfingerOnly) { throw new Error("Unable to find webfinger"); } lrdd(resource, options, this); }, callback ); }; var discover = function(address, callback) { if (address.indexOf("@") !== -1) { webfinger(address, callback); } else { hostmeta(address, callback); } }; exports.xrd2jrd = xrd2jrd; exports.webfinger = webfinger; exports.lrdd = lrdd; exports.hostmeta = hostmeta; exports.discover = discover; webfinger-0.4.2/package.json000066400000000000000000000016501217152717100157610ustar00rootroot00000000000000{ "name": "webfinger", "description": "Client library for Host Meta (RFC 6415) and Webfinger", "homepage": "http://github.com/e14n/webfinger", "version": "0.4.2", "keywords": ["webfinger", "hostmeta", "discovery", "xrd", "jrd", "lrdd"], "engines": { "node": ">=0.8.x" }, "author": "Evan Prodromou ", "scripts": { "test": "vows -i test/*-test.js" }, "main": "./lib/webfinger.js", "directories": { "lib": "./lib/" }, "devDependencies": { "vows": "0.7.x", "express": "3.0.x" }, "dependencies": { "step": "0.0.x", "xml2js": "0.1.x" }, "repository": { "type": "git", "url": "git://github.com/e14n/webfinger.git" }, "licenses": [ { "type": "Apache 2.0", "url": "http://www.apache.org/licenses/LICENSE-2.0.html" } ] }webfinger-0.4.2/test/000077500000000000000000000000001217152717100144505ustar00rootroot00000000000000webfinger-0.4.2/test/data/000077500000000000000000000000001217152717100153615ustar00rootroot00000000000000webfinger-0.4.2/test/data/localhost.crt000066400000000000000000000011571217152717100200670ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIBnzCCAQgCCQDKOko9NRDKHzANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDDAls b2NhbGhvc3QwHhcNMTIwODI4MjAyNTM5WhcNMjIwODI2MjAyNTM5WjAUMRIwEAYD VQQDDAlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMAWKsrC LL6FL9SZL100YpBojXXmu2OwHwPy1DsqIFJRQv2G5lL7+ZMnpgxd4gOKjtq2J5KN vCBgwAnqG1FVJnABFnj/M3Cj6Rrl5ByaJ6gnizPvoDbR46X/X9/Xsip/e/eNssOz M0p70YN5XxxERxy4EGbP8BuNzfBPuAF7QWb5AgMBAAEwDQYJKoZIhvcNAQEFBQAD gYEAXJJTO/GWlsZ5ef4OUnY76gj2vWIC4AVI/hRWGMmEortnRC7apd+OPhb16dI1 N82HkbOOgLnOEpvrvJaTUL0obrdD/appOsPT2Ipl41Q2Jq8uYb62Fm7W/Dom3rbx y1EsYAYATs7d6AfpJnKoUeXANvvp50iS8jMpN5hNlBSSQYo= -----END CERTIFICATE----- webfinger-0.4.2/test/data/localhost.csr000066400000000000000000000010321217152717100200560ustar00rootroot00000000000000-----BEGIN CERTIFICATE REQUEST----- MIIBUzCBvQIBADAUMRIwEAYDVQQDDAlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEB BQADgY0AMIGJAoGBAMAWKsrCLL6FL9SZL100YpBojXXmu2OwHwPy1DsqIFJRQv2G 5lL7+ZMnpgxd4gOKjtq2J5KNvCBgwAnqG1FVJnABFnj/M3Cj6Rrl5ByaJ6gnizPv oDbR46X/X9/Xsip/e/eNssOzM0p70YN5XxxERxy4EGbP8BuNzfBPuAF7QWb5AgMB AAGgADANBgkqhkiG9w0BAQUFAAOBgQCIbYFwMWWL5o+b3J+Mu4/WhltHqCJKIw9K rB70/S16pInp36XgX282tWQ2+BEzEZFv8SasHPPM7DwJUS20C5Muo0ZhOhhQpNB4 2/a5D1+ui94fvbJ4O5svmwsUzYVlaYEh9LYJQxamN9ATG4ajaYVh+U8K3azlNZHF r6K9CQp+Jw== -----END CERTIFICATE REQUEST----- webfinger-0.4.2/test/data/localhost.key000066400000000000000000000015671217152717100200740ustar00rootroot00000000000000-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQDAFirKwiy+hS/UmS9dNGKQaI115rtjsB8D8tQ7KiBSUUL9huZS +/mTJ6YMXeIDio7atieSjbwgYMAJ6htRVSZwARZ4/zNwo+ka5eQcmieoJ4sz76A2 0eOl/1/f17Iqf3v3jbLDszNKe9GDeV8cREccuBBmz/Abjc3wT7gBe0Fm+QIDAQAB AoGAGKn//p7mHeR+Gr88nKwgR8iU+WGSCB/SK7CfXaVwFwHGJ0WOB3PBPQrnQElB vxCofR7Mf/3g/QtPPTapIU1crOX66jK5Zcz95P55F238XGqyX7gQKzUiFR5hTAfG 9OSNNfeI9psqnYQFfGeImdfu1cahgP8INXagmnpuVdDZpt0CQQDrP4wpVe4wEqct gNqfLYFzxx/eyAhtgXWUxhufpi8tjXo8cwUfcpbGS1suSS7yKL/gZS8+45C/jdkf KPHpQITDAkEA0Qft6UGcqg8JgaAyGQpSyB/hAS48h3N903PB0DelqsKixkDtNb4Q oOXhziSUMuphbAcaOT7IuBnobiNrtmd5kwJAK3gsoB6+yqdHuQLMYwl3mDs9Sl9Q H1wCrCEHTbLZmONBqRXf5nW4IqAeEyl2wUyCWCaaWlaWkq7VZgqc2OsRHQJAQVSs HAIgt9n5S6VI4yCh3OBxz4+m5WLIScVdJvmtcqBghXwXZ3ue8NrIZ0hxdTRh/IR/ wrKHw1p9labGbH0MtwJBANkVCF7wgPNHMsdAmbqzYTsxEP1ArE/ujXG7CrWHhUMi ytT9JFr+HI21h6oFm8bAiXusGkpkllcjIilIHufKkBs= -----END RSA PRIVATE KEY----- webfinger-0.4.2/test/hostmeta-404-test.js000066400000000000000000000041611217152717100201160ustar00rootroot00000000000000// hostmeta-404-test.js // // Test webfinger when the hostmeta endpoint is missing // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("Test missing hostmeta endpoint"); suite.addBatch({ "When we run an HTTP app that does not support host-meta": { topic: function() { var app = express(), callback = this.callback; app.get("/.well-known/host-meta", function(req, res) { res.send(404, 'No such resource'); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data": { topic: function() { var callback = this.callback; wf.hostmeta("localhost", function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success!")); } }); }, "it works": function(err, jrd) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-both-test.js000066400000000000000000000065041217152717100205460ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that supports both host-meta and host-meta.json": { topic: function() { var app = express(), callback = this.callback; app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data": { topic: function() { wf.hostmeta("localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the JRD link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "lrdd"); assert.include(jrd.links[0], "type"); assert.equal(jrd.links[0].type, "application/json"); assert.include(jrd.links[0], "template"); assert.equal(jrd.links[0].template, "http://localhost/lrdd.json?uri={uri}"); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-https-json-test.js000066400000000000000000000063311217152717100217210ustar00rootroot00000000000000// hostmeta-https-json-test.js // // Test the module interface // // Copyright 2012-2013, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); var suite = vows.describe("RFC6415 (host-meta) interface"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; suite.addBatch({ "When we run an HTTPS app that just supports host-meta with JRD": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data": { topic: function() { wf.hostmeta("localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "lrdd"); assert.include(jrd.links[0], "type"); assert.equal(jrd.links[0].type, "application/json"); assert.include(jrd.links[0], "template"); assert.equal(jrd.links[0].template, "http://localhost/lrdd.json?uri={uri}"); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-https-no-redirect-test.js000066400000000000000000000071731217152717100231700ustar00rootroot00000000000000// hostmeta-https-no-redirect-test.js // // Test the httpsOnly flag for the webfinger function // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var Step = require("step"), fs = require("fs"), path = require("path"), https = require("https"), assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("hostmeta shouldn't redirect to http if https-only flag set"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; suite.addBatch({ "When we run an HTTPS app that redirects to an HTTP app for hostmeta": { topic: function() { var hm = express(), hm2 = express(), callback = this.callback; // parse queries hm.use(express.query()); hm.get("/.well-known/host-meta.json", function(req, res) { res.redirect(307, "http://localhost/.well-known/host-meta.json"); }); // parse queries hm2.use(express.query()); hm2.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); hm.on("error", function(err) { callback(err, null); }); hm2.on("error", function(err) { callback(err, null); }); Step( function() { var opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, hm).listen(443, this.parallel()); hm2.listen(80, this.parallel()); }, function(err) { callback(null, hm, hm2); } ); }, "it works": function(err, hm, hm2) { assert.ifError(err); assert.isFunction(hm); assert.isFunction(hm2); }, teardown: function(hm, hm2) { if (hm && hm.close) { hm.close(); } if (hm2 && hm2.close) { hm2.close(); } }, "and we get hostmeta data with httpsOnly flag set": { topic: function() { var callback = this.callback; wf.hostmeta("localhost", {httpsOnly: true}, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err, jrd) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-https-only-test.js000066400000000000000000000047651217152717100217420ustar00rootroot00000000000000// hostmeta-json-test.js // // Test flag to refuse falling back to http for hostmeta // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("Flag to prevent falling back to http"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with JRD": { topic: function() { var app = express(), callback = this.callback; app.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data with the HTTPS-only flag": { topic: function() { var callback = this.callback; wf.hostmeta("localhost", {httpsOnly: true}, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success!")); } }); }, "it fails correctly": function(err) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-https-test.js000066400000000000000000000064711217152717100207570ustar00rootroot00000000000000// hostmeta-https-test.js // // Test finding hostmeta by https // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); var suite = vows.describe("RFC6415 (host-meta) interface over https with XRD only"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; suite.addBatch({ "When we run an HTTPS app that just supports host-meta with XRD": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data": { topic: function() { wf.hostmeta("localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "lrdd"); assert.include(jrd.links[0], "type"); assert.equal(jrd.links[0].type, "application/xrd+xml"); assert.include(jrd.links[0], "template"); assert.equal(jrd.links[0].template, "https://localhost/lrdd?uri={uri}"); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-invalid-test.js000066400000000000000000000033461217152717100212410ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012-2013 E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("Test hostmeta for bad domain"); var badDomain = function(domain) { return { topic: function() { var callback = this.callback; wf.hostmeta(domain, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success!")); } }); }, "it works": function(err, jrd) { assert.ifError(err); } }; }; suite.addBatch({ "When we get host-meta data for a .invalid domain": badDomain("host-meta.invalid"), "When we get host-meta data for a .example domain": badDomain("host-meta.example"), "When we get host-meta data for example.com": badDomain("example.com"), "When we get host-meta data for example.org": badDomain("example.org"), "When we get host-meta data for example.net": badDomain("example.net") }); suite["export"](module); webfinger-0.4.2/test/hostmeta-json-test.js000066400000000000000000000055301217152717100205610ustar00rootroot00000000000000// hostmeta-json-test.js // // Test host-meta.json support // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with JRD": { topic: function() { var app = express(), callback = this.callback; app.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data": { topic: function() { wf.hostmeta("localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "lrdd"); assert.include(jrd.links[0], "type"); assert.equal(jrd.links[0].type, "application/json"); assert.include(jrd.links[0], "template"); assert.equal(jrd.links[0].template, "http://localhost/lrdd.json?uri={uri}"); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-negotiated-test.js000066400000000000000000000072251217152717100217360ustar00rootroot00000000000000// hostmeta-json-test.js // // Test host-meta.json support // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that supports host-meta with JRD or XRD with negotiation": { topic: function() { var app = express(), callback = this.callback, jrd = function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }, xrd = function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }; app.get("/.well-known/host-meta", function(req, res) { if (req.headers.hasOwnProperty("accept") && req.headers.accept.match(/^application\/json/)) { jrd(req, res); } else { xrd(req, res); } }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data": { topic: function() { wf.hostmeta("localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the JRD link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "lrdd"); assert.include(jrd.links[0], "type"); assert.equal(jrd.links[0].type, "application/json"); assert.include(jrd.links[0], "template"); assert.equal(jrd.links[0].template, "http://localhost/lrdd.json?uri={uri}"); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-redirect-to-home-test.js000066400000000000000000000102121217152717100227500ustar00rootroot00000000000000// hostmeta-https-test.js // // Test finding hostmeta by https // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var Step = require("step"), assert = require("assert"), vows = require("vows"), express = require("express"), http = require("http"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just redirects to the HTTP home page": { topic: function() { var app = express(), sapp = express(), opts, cnt = 0, callback = this.callback; app.get("/", function(req, res) { res.status(200).set("Content-Type", "text/html"); res.end("Localhost

Localhost

"); }); app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.on("error", function(err) { callback(err, null); }); sapp.get("/.well-known/host-meta", function(req, res) { res.status(302).set("Location", "http://localhost/").send("Redirect"); }); sapp.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; Step( function() { https.createServer(opts, sapp).listen(443, this.parallel()); http.createServer(app).listen(80, this.parallel()); }, function() { callback(null, app, sapp); } ); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app, sapp) { if (app && app.close) { app.close(); } if (sapp && sapp.close) { sapp.close(); } }, "and we get its host-meta data": { topic: function() { wf.hostmeta("localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "lrdd"); assert.include(jrd.links[0], "type"); assert.equal(jrd.links[0].type, "application/xrd+xml"); assert.include(jrd.links[0], "template"); assert.equal(jrd.links[0].template, "http://localhost/lrdd?uri={uri}"); } } } }); suite["export"](module); webfinger-0.4.2/test/hostmeta-test.js000066400000000000000000000056321217152717100176150ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get its host-meta data": { topic: function() { wf.hostmeta("localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "lrdd"); assert.include(jrd.links[0], "type"); assert.equal(jrd.links[0].type, "application/xrd+xml"); assert.include(jrd.links[0], "template"); assert.equal(jrd.links[0].template, "http://localhost/lrdd?uri={uri}"); } } } }); suite["export"](module); webfinger-0.4.2/test/lrdd-server-only-supports-bare-address.js000066400000000000000000000072601217152717100244520ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/lrdd", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { res.send(404, "Unrecognized object type\n"); return; } res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+uri+""+ ""+ ""); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a webfinger's metadata": { topic: function() { wf.webfinger("acct:alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "http://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/lrdd-test.js000066400000000000000000000071701217152717100167150ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/lrdd", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+uri+""+ ""+ ""); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get metadata with lrdd": { topic: function() { wf.lrdd("alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "http://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/module-test.js000066400000000000000000000027121217152717100172520ustar00rootroot00000000000000// module-test.js // // Test the module interface // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"); var suite = vows.describe("Webfinger module interface"); suite.addBatch({ "When we get the app module": { topic: function() { return require("../lib/webfinger"); }, "there is one": function(mod) { assert.isObject(mod); }, "it has the xrd2jrd() export": function(mod) { assert.isFunction(mod.xrd2jrd); }, "it has the webfinger() export": function(mod) { assert.isFunction(mod.webfinger); }, "it has the hostmeta() export": function(mod) { assert.isFunction(mod.hostmeta); }, "it has the discover() export": function(mod) { assert.isFunction(mod.discover); } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-acct-uri-test.js000066400000000000000000000065641217152717100214530ustar00rootroot00000000000000// webfinger-only-test.js // // Test discovery just using Webfinger without host-meta // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ subject: uri, links: [ { rel: "profile", href: "https://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a Webfinger": { topic: function() { wf.webfinger("acct:alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "https://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-extended-test.js000066400000000000000000000132351217152717100215350ustar00rootroot00000000000000// webfinger-extended-test.js // // Test extended properties in XRD output // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/lrdd", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+uri+"\n"+ "http://localhost/profile/"+username+"\n"+ "http://localhost/user/1\n"+ "\n"+ ""+ ""+username+""+ ""); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a webfinger's metadata": { topic: function() { wf.webfinger("alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the links": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 2); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "http://localhost/profile/alice"); assert.isObject(jrd.links[1]); assert.include(jrd.links[1], "rel"); assert.equal(jrd.links[1].rel, "http://apinamespace.org/atom"); assert.include(jrd.links[1], "type"); assert.equal(jrd.links[1].type, "application/atomsvc+xml"); assert.include(jrd.links[1], "href"); assert.equal(jrd.links[1].href, "http://localhost/app/alice.atom"); assert.include(jrd.links[1], "properties"); assert.isObject(jrd.links[1].properties); assert.include(jrd.links[1].properties, "http://apinamespace.org/atom/username"); assert.equal(jrd.links[1].properties["http://apinamespace.org/atom/username"], "alice"); }, "it has the subject": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "subject"); assert.isString(jrd.subject); assert.equal(jrd.subject, "acct:alice@localhost"); }, "it has the alias": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "aliases"); assert.isArray(jrd.aliases); assert.lengthOf(jrd.aliases, 2); assert.isString(jrd.aliases[0]); assert.equal(jrd.aliases[0], "http://localhost/profile/alice"); assert.isString(jrd.aliases[1]); assert.equal(jrd.aliases[1], "http://localhost/user/1"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-https-no-redirect-test.js000066400000000000000000000071261217152717100233120ustar00rootroot00000000000000// webfinger-https-no-redirect-test.js // // Test that requests for Webfinger won't redirect to HTTP for redirect // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var Step = require("step"), assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("Webfinger should not redirect to HTTP"); suite.addBatch({ "When we run an HTTPS app that redirects to HTTP for Webfinger": { topic: function() { var app = express(), sapp = express(), opts, callback = this.callback; // Secure app redirects to insecure sapp.get("/.well-known/webfinger", function(req, res) { var host = req.header('Host'); res.redirect(303, 'http://'+host+req.url); }); app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, parts = uri.split("@"), username = parts[0], hostname = parts[1]; res.json({ subject: uri, links: [ { rel: "profile", href: "https://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; Step( function() { https.createServer(opts, sapp).listen(443, this.parallel()); app.listen(80, this.parallel()); }, function(err) { callback(null, app, sapp); } ); }, "it works": function(err, app, sapp) { assert.ifError(err); assert.isFunction(app); assert.isFunction(sapp); }, teardown: function(app, sapp) { if (app && app.close) { app.close(); } if (sapp && sapp.close) { sapp.close(); } }, "and we get a Webfinger": { topic: function() { var callback = this.callback; wf.webfinger("alice@localhost", function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-https-only-for-lrdd-test.js000066400000000000000000000077351217152717100235750ustar00rootroot00000000000000// webfinger-https-only-for-lrdd-test.js // // Test the httpsOnly flag for the webfinger function // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var Step = require("step"), fs = require("fs"), path = require("path"), https = require("https"), assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("webfinger httpsOnly flag disallows redirect to HTTP-only LRDD"); suite.addBatch({ "When we run an HTTPS app that uses an HTTP app for LRDD": { topic: function() { var hm = express(), lrdd = express(), callback = this.callback; // parse queries hm.use(express.query()); hm.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); // parse queries lrdd.use(express.query()); lrdd.get("/lrdd.json", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; res.json({ links: [ { rel: "profile", href: "http://localhost/profile/" + username } ] }); }); hm.on("error", function(err) { callback(err, null); }); lrdd.on("error", function(err) { callback(err, null); }); Step( function() { var opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, hm).listen(443, this.parallel()); lrdd.listen(80, this.parallel()); }, function(err) { callback(null, hm, lrdd); } ); }, "it works": function(err, hm, lrdd) { assert.ifError(err); assert.isFunction(hm); assert.isFunction(lrdd); }, teardown: function(hm, lrdd) { if (hm && hm.close) { hm.close(); } if (lrdd && lrdd.close) { lrdd.close(); } }, "and we get a webfinger with https-only flag set": { topic: function() { var callback = this.callback; wf.webfinger("alice@localhost", null, {httpsOnly: true}, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err, jrd) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-https-only-no-hostmeta-redirect-test.js000066400000000000000000000105431217152717100261100ustar00rootroot00000000000000// webfinger-https-only-no-hostmeta-redirect-test.js // // Test that when httpsOnly is set, we don't follow redirects in the hostmeta endpoint // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var Step = require("step"), fs = require("fs"), path = require("path"), https = require("https"), assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("hostmeta shouldn't redirect to http if https-only flag set"); suite.addBatch({ "When we run an HTTPS app that redirects to an HTTP app for hostmeta": { topic: function() { var hm = express(), hm2 = express(), callback = this.callback; // parse queries hm.use(express.query()); // secure app redirects to insecure hm.get("/.well-known/host-meta.json", function(req, res) { res.redirect(307, "http://localhost/.well-known/host-meta.json"); }); // parse queries hm2.use(express.query()); hm2.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); hm2.get("/lrdd.json", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ links: [ { rel: "profile", href: "http://localhost/profile/" + username } ] }); }); hm.on("error", function(err) { callback(err, null); }); hm2.on("error", function(err) { callback(err, null); }); Step( function() { var opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, hm).listen(443, this.parallel()); hm2.listen(80, this.parallel()); }, function(err) { callback(null, hm, hm2); } ); }, "it works": function(err, hm, hm2) { assert.ifError(err); assert.isFunction(hm); assert.isFunction(hm2); }, teardown: function(hm, hm2) { if (hm && hm.close) { hm.close(); } if (hm2 && hm2.close) { hm2.close(); } }, "and we get webfinger data with httpsOnly flag set": { topic: function() { var callback = this.callback; wf.webfinger("alice@localhost", null, {httpsOnly: true}, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err, jrd) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-https-only-no-lrdd-redirect-test.js000066400000000000000000000106371217152717100252150ustar00rootroot00000000000000// webfinger-https-only-no-hostmeta-redirect-test.js // // Test that when httpsOnly is set, we don't follow redirects in the hostmeta endpoint // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var Step = require("step"), fs = require("fs"), path = require("path"), https = require("https"), assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("lrdd shouldn't redirect to http if https-only flag set"); suite.addBatch({ "When we run an HTTPS app that redirects to an HTTP app for hostmeta": { topic: function() { var hm = express(), hm2 = express(), callback = this.callback; // parse queries hm.use(express.query()); // secure host-meta uses secure lrdd hm.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "https://localhost/lrdd.json?uri={uri}" } ] }); }); hm.get("/lrdd.json", function(req, res) { var host = req.header('Host'); res.redirect(303, 'http://'+host+req.url); }); // secure lrdd redirects to insecure lrdd // parse queries hm2.use(express.query()); hm2.get("/lrdd.json", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ links: [ { rel: "profile", href: "http://localhost/profile/" + username } ] }); }); hm.on("error", function(err) { callback(err, null); }); hm2.on("error", function(err) { callback(err, null); }); Step( function() { var opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, hm).listen(443, this.parallel()); hm2.listen(80, this.parallel()); }, function(err) { callback(null, hm, hm2); } ); }, "it works": function(err, hm, hm2) { assert.ifError(err); assert.isFunction(hm); assert.isFunction(hm2); }, teardown: function(hm, hm2) { if (hm && hm.close) { hm.close(); } if (hm2 && hm2.close) { hm2.close(); } }, "and we get webfinger data with httpsOnly flag set": { topic: function() { var callback = this.callback; wf.webfinger("alice@localhost", null, {httpsOnly: true}, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err, jrd) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-https-only-test.js000066400000000000000000000063011217152717100220520ustar00rootroot00000000000000// webfinger-https-only-test.js // // Test the httpsOnly flag for the webfinger function // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("webfinger httpsOnly flag causes error"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); app.get("/lrdd.json", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ links: [ { rel: "profile", href: "http://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a webfinger with https-only flag set": { topic: function() { var callback = this.callback; wf.webfinger("alice@localhost", null, {httpsOnly: true}, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err, jrd) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-https-test.js000066400000000000000000000076711217152717100211060ustar00rootroot00000000000000// hostmeta-https-test.js // // Test finding hostmeta by https // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports host-meta with XRD": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/lrdd", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+uri+""+ ""+ ""); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a Webfinger": { topic: function() { wf.webfinger("alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "https://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-invalid-test.js000066400000000000000000000034731217152717100213660ustar00rootroot00000000000000// webfinger-invalid-test.js // // Test webfinger when the domain is invalid // // Copyright 2012-2013 E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("Test webfinger for bad domain"); var badDomain = function(domain) { return { topic: function() { var callback = this.callback; wf.webfinger("user@"+domain, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success!")); } }); }, "it works": function(err, jrd) { assert.ifError(err); } }; }; suite.addBatch({ "When we get webfinger data for a user in a .invalid domain": badDomain("webfinger.invalid"), "When we get webfinger data for a user in a .example domain": badDomain("webfinger.example"), "When we get webfinger data for a user in example.com": badDomain("example.com"), "When we get webfinger data for a user in example.org": badDomain("example.org"), "When we get webfinger data for a user in example.net": badDomain("example.net") }); suite["export"](module); webfinger-0.4.2/test/webfinger-json-test.js000066400000000000000000000066221217152717100207100ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta.json", function(req, res) { res.json({ links: [ { rel: "lrdd", type: "application/json", template: "http://localhost/lrdd.json?uri={uri}" } ] }); }); app.get("/lrdd.json", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ links: [ { rel: "profile", href: "http://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a webfinger's metadata": { topic: function() { wf.webfinger("alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "http://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-nonacct-uri-test.js000066400000000000000000000066121217152717100221600ustar00rootroot00000000000000// hostmeta-test.js // // Test getting LRDD data for a non-acct URI // // Copyright 2013, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/lrdd", function(req, res) { var uri = req.query.uri; res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+uri+""+ ""+ ""); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get an http URL's metadata": { topic: function() { wf.webfinger("http://localhost/profile/alice", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "feed"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "http://localhost/profile/alice/feed"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-only-flag-fail-test.js000066400000000000000000000063221217152717100225350ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012, StatusNet Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/lrdd", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+uri+""+ ""+ ""); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a webfinger with the webfingerOnly flag set": { topic: function() { var callback = this.callback; wf.webfinger("alice@localhost", null, {webfingerOnly: true}, function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-only-flag-test.js000066400000000000000000000066401217152717100216270ustar00rootroot00000000000000// webfinger-only-test.js // // Test discovery just using Webfinger without host-meta // // Copyright 2012, StatusNet Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ subject: uri, links: [ { rel: "profile", href: "https://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a Webfinger with the webfingerOnly flag": { topic: function() { wf.webfinger("alice@localhost", null, {webfingerOnly: true}, this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "https://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-only-lrdd-test.js000066400000000000000000000060611217152717100216400ustar00rootroot00000000000000// webfinger-only-lrdd-test.js // // Test LRDD discovery on a server that only supports Webfinger // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ subject: uri, links: [ { rel: "profile", href: "https://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we do LRDD discovery": { topic: function() { var callback = this.callback; wf.lrdd("alice@localhost", function(err, jrd) { if (err) { callback(null); } else { callback(new Error("Unexpected success")); } }); }, "it fails correctly": function(err) { assert.ifError(err); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-only-multiple-rel-test.js000066400000000000000000000114361217152717100233300ustar00rootroot00000000000000// webfinger-only-multiple-rel-test.js // // Test discovery using multiple rel parameters // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, rel = req.query.rel, parts = uri.split("@"), username = parts[0], hostname = parts[1], result = { subject: uri, links: [] }, type, types; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } types = { "profile": function(username) { return "https://localhost/profile/" + username; }, "avatar": function(username) { return "https://localhost/avatar/" + username + ".png"; }, "hub": function() { return "https://localhost/hub"; } }; for (type in types) { if (types.hasOwnProperty(type)) { if (!rel || (rel.indexOf && rel.indexOf(type) !== -1) || rel == type) { result.links.push({rel: type, href: types[type](username)}); } } } res.json(result); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get multiple Webfinger rels": { topic: function() { wf.webfinger("alice@localhost", ["profile", "avatar"], this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the links": function(err, jrd) { var profiles, avatars; assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 2); profiles = jrd.links.filter(function(item) { return item.rel == "profile"; }); assert.lengthOf(profiles, 1); assert.isObject(profiles[0]); assert.include(profiles[0], "rel"); assert.equal(profiles[0].rel, "profile"); assert.include(profiles[0], "href"); assert.equal(profiles[0].href, "https://localhost/profile/alice"); avatars = jrd.links.filter(function(item) { return item.rel == "avatar"; }); assert.lengthOf(avatars, 1); assert.isObject(avatars[0]); assert.include(avatars[0], "rel"); assert.equal(avatars[0].rel, "avatar"); assert.include(avatars[0], "href"); assert.equal(avatars[0].href, "https://localhost/avatar/alice.png"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-only-nonacct-uri-test.js000066400000000000000000000061611217152717100231360ustar00rootroot00000000000000// webfinger-only-test.js // // Test discovery just using Webfinger without host-meta // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource; res.json({ subject: uri, links: [ { rel: "feed", href: uri + "/feed" } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get an http URL's metadata": { topic: function() { wf.webfinger("http://localhost/profile/alice", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "feed"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "http://localhost/profile/alice/feed"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-only-test.js000066400000000000000000000065571217152717100207270ustar00rootroot00000000000000// webfinger-only-test.js // // Test discovery just using Webfinger without host-meta // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.json({ subject: uri, links: [ { rel: "profile", href: "https://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a Webfinger": { topic: function() { wf.webfinger("alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "https://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-only-with-rel-test.js000066400000000000000000000122661217152717100224520ustar00rootroot00000000000000// webfinger-only-test.js // // Test discovery just using Webfinger without host-meta // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, rel = req.query.rel, parts = uri.split("@"), username = parts[0], hostname = parts[1], result = { subject: uri, links: [] }; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } if (!rel || rel == "profile") { result.links.push({rel: "profile", href: "https://localhost/profile/" + username}); } if (!rel || rel == "avatar") { result.links.push({rel: "avatar", href: "https://localhost/avatar/" + username + ".png"}); } res.json(result); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a single Webfinger rel": { topic: function() { wf.webfinger("alice@localhost", "profile", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the links": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "https://localhost/profile/alice"); } }, "and we get the other Webfinger rel": { topic: function() { wf.webfinger("alice@localhost", "avatar", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the links": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "avatar"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "https://localhost/avatar/alice.png"); } }, "and we get an unrecognized Webfinger rel": { topic: function() { wf.webfinger("alice@localhost", "http://web.example/unrecognized", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has no links": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 0); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-server-only-takes-bare-address.js000066400000000000000000000066361217152717100247130ustar00rootroot00000000000000// webfinger-only-test.js // // Test discovery just using Webfinger without host-meta // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), https = require("https"), wf = require("../lib/webfinger"), fs = require("fs"), path = require("path"); process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTPS app that just supports Webfinger": { topic: function() { var app = express(), opts, callback = this.callback; app.get("/.well-known/webfinger", function(req, res) { var uri = req.query.resource, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { res.send(404, "Unrecognized object type\n"); return; } res.json({ subject: uri, links: [ { rel: "profile", href: "https://localhost/profile/" + username } ] }); }); app.on("error", function(err) { callback(err, null); }); opts = {key: fs.readFileSync(path.join(__dirname, "data", "localhost.key")), cert: fs.readFileSync(path.join(__dirname, "data", "localhost.crt"))}; https.createServer(opts, app).listen(443, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a Webfinger": { topic: function() { wf.webfinger("acct:alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "https://localhost/profile/alice"); } } } }); suite["export"](module); webfinger-0.4.2/test/webfinger-test.js000066400000000000000000000072011217152717100177330ustar00rootroot00000000000000// hostmeta-test.js // // Test the module interface // // Copyright 2012, E14N https://e14n.com/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. var assert = require("assert"), vows = require("vows"), express = require("express"), wf = require("../lib/webfinger"); var suite = vows.describe("RFC6415 (host-meta) interface"); suite.addBatch({ "When we run an HTTP app that just supports host-meta with XRD": { topic: function() { var app = express(), callback = this.callback; // parse queries app.use(express.query()); app.get("/.well-known/host-meta", function(req, res) { res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+ ""); }); app.get("/lrdd", function(req, res) { var uri = req.query.uri, parts = uri.split("@"), username = parts[0], hostname = parts[1]; if (username.substr(0, 5) == "acct:") { username = username.substr(5); } res.status(200); res.set("Content-Type", "application/xrd+xml"); res.end("\n"+ "\n" + ""+uri+""+ ""+ ""); }); app.on("error", function(err) { callback(err, null); }); app.listen(80, function() { callback(null, app); }); }, "it works": function(err, app) { assert.ifError(err); }, teardown: function(app) { if (app && app.close) { app.close(); } }, "and we get a webfinger's metadata": { topic: function() { wf.webfinger("alice@localhost", this.callback); }, "it works": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); }, "it has the link": function(err, jrd) { assert.ifError(err); assert.isObject(jrd); assert.include(jrd, "links"); assert.isArray(jrd.links); assert.lengthOf(jrd.links, 1); assert.isObject(jrd.links[0]); assert.include(jrd.links[0], "rel"); assert.equal(jrd.links[0].rel, "profile"); assert.include(jrd.links[0], "href"); assert.equal(jrd.links[0].href, "http://localhost/profile/alice"); } } } }); suite["export"](module);