├── README.md ├── vuforia.js ├── .gitignore ├── package.json ├── LICENSE └── lib ├── util.js └── client.js /README.md: -------------------------------------------------------------------------------- 1 | And I.. Am... Iron Man -------------------------------------------------------------------------------- /vuforia.js: -------------------------------------------------------------------------------- 1 | var vuforia = function () { 2 | 3 | var client = require(__dirname + '/lib/client'); 4 | var util = require(__dirname + '/lib/util'); 5 | 6 | return { 7 | 8 | 'client': client, 9 | 'util' : util 10 | }; 11 | 12 | }; 13 | 14 | module.exports = vuforia(); 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Deployed apps should consider commenting this line out: 24 | # see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git 25 | node_modules 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vuforiajs", 3 | "version": "0.3.0", 4 | "description": "Node.js client for the Vuforia Web Services API (VWS API) and Cloud Recognition API (CloudReco API)", 5 | "main": "vuforia.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/pwasem/vuforiajs" 12 | }, 13 | "keywords": [ 14 | "vuforia", 15 | "vws", 16 | "api", 17 | "augmented", 18 | "reality", 19 | "cloud", 20 | "target", 21 | "image", 22 | "recognition" 23 | ], 24 | "author": "pascal.wasem@googlemail.com", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/pwasem/vuforiajs/issues" 28 | }, 29 | "homepage": "https://github.com/pwasem/vuforiajs" 30 | } 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Pascal Wasem 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /lib/util.js: -------------------------------------------------------------------------------- 1 | const boundary = "----------ThIs_Is_tHe_bouNdaRY_$"; 2 | 3 | var util = function () { 4 | 5 | var crypto = require('crypto'); 6 | var fs = require('fs'); 7 | 8 | var timestamp = function() { 9 | 10 | var now = new Date(); 11 | return now.toUTCString(); 12 | }; 13 | 14 | var encodeBase64 = function(input) { 15 | 16 | var serialization = input.toString(); 17 | 18 | var buffer = new Buffer(serialization); 19 | 20 | return buffer.toString('base64'); 21 | }; 22 | 23 | var decodeBase64 = function(input) { 24 | 25 | var buffer = new Buffer(input,'base64'); 26 | 27 | return buffer.toString(); 28 | }; 29 | 30 | var encodeFileBase64 = function(path) { 31 | 32 | var buffer = fs.readFileSync(path); 33 | 34 | return buffer.toString('base64'); 35 | }; 36 | 37 | var hashHmacSha1Base64 = function (key, input) { 38 | 39 | var hmacSha1base64 = 40 | 41 | crypto 42 | .createHmac('sha1', key) 43 | .update(input) 44 | .digest('base64'); 45 | 46 | return hmacSha1base64; 47 | 48 | }; 49 | 50 | var hashMd5Hex = function (input) { 51 | 52 | var md5 = 53 | 54 | crypto 55 | .createHash('md5') 56 | .update(input) 57 | .digest('hex'); 58 | 59 | return md5; 60 | }; 61 | 62 | var createStringToSign = function (request) { 63 | 64 | var newLine = '\n'; 65 | 66 | var stringToSign = 67 | 68 | request.method + newLine + 69 | hashMd5Hex(request.body) + newLine + 70 | request.type + newLine + 71 | request.timestamp + newLine + 72 | request.path; 73 | 74 | return stringToSign; 75 | 76 | }; 77 | 78 | var createSignature = function (request) { 79 | 80 | var stringToSign = createStringToSign(request); 81 | 82 | var signature = hashHmacSha1Base64(request.secretKey, stringToSign); 83 | 84 | return signature; 85 | }; 86 | 87 | var createAuthorization = function (request) { 88 | 89 | var signature = createSignature(request); 90 | 91 | var authorization = 'VWS ' + request.accessKey + ':' + signature; 92 | 93 | return authorization; 94 | }; 95 | 96 | var createCloudRecoQueryBody = function (binaryImage, max_num_results) { 97 | var body = ""; 98 | 99 | if (max_num_results !== undefined) { 100 | if (isNaN(max_num_results)) { 101 | throw new Error("max_num_results is not a number"); 102 | } else if (max_num_results < 1 || max_num_results > 10) { 103 | throw new Error("max_num_results is out of allowed interval [1-10]"); 104 | } else { 105 | var body = body + 106 | "--"+boundary + "\r\n" + 107 | 'Content-Disposition: form-data; name="max_num_results"' + "\r\n\r\n" + 108 | max_num_results + "\r\n"; 109 | } 110 | } 111 | 112 | var body = body + 113 | "--"+boundary + "\r\n" + 114 | 'Content-Disposition: form-data; name="image"; filename="image.jpg"' + "\r\n" + 115 | "Content-Type: image/jpeg\r\n\r\n" + 116 | binaryImage + "\r\n" + 117 | "--" + boundary + "--\r\n"; 118 | 119 | return Buffer.from(body, 'binary'); 120 | }; 121 | 122 | var createCloudRecoQueryContentTypeHeader = function () { 123 | return "multipart/form-data; boundary=" + boundary; 124 | }; 125 | 126 | return { 127 | 128 | 'timestamp' : timestamp, 129 | 'encodeBase64' : encodeBase64, 130 | 'decodeBase64' : decodeBase64, 131 | 'encodeFileBase64' : encodeFileBase64, 132 | 'hashHmacSha1Base64' : hashHmacSha1Base64, 133 | 'hashMd5Hex': hashMd5Hex, 134 | 'createAuthorization' : createAuthorization, 135 | 'createCloudRecoQueryBody' : createCloudRecoQueryBody, 136 | 'createCloudRecoQueryContentTypeHeader' : createCloudRecoQueryContentTypeHeader 137 | }; 138 | 139 | }; 140 | 141 | module.exports = util; -------------------------------------------------------------------------------- /lib/client.js: -------------------------------------------------------------------------------- 1 | const vwsHostname = 'vws.vuforia.com'; 2 | const cloudRecoHostname = 'cloudreco.vuforia.com'; 3 | 4 | var client = function (options) { 5 | 6 | var https = require('https'); 7 | var util = require(__dirname + '/util')(); 8 | 9 | var doHttpsRequest = function (httpsOptions, body, callback) { 10 | 11 | var request = https.request(httpsOptions, function (response) { 12 | 13 | var data = ''; 14 | 15 | response.setEncoding('utf8'); 16 | 17 | response.on('data', function (chunk) { 18 | 19 | data += chunk; 20 | }); 21 | 22 | response.on('end', function () { 23 | 24 | try { 25 | 26 | var result = JSON.parse(data); 27 | 28 | if (response.statusCode === 200 || response.statusCode === 201) { 29 | 30 | callback(null, result); 31 | 32 | } else { 33 | 34 | var error = new Error(result.result_code); 35 | callback(error, result); 36 | } 37 | 38 | } catch (error) { 39 | 40 | callback(error, {}); 41 | } 42 | }); 43 | }); 44 | 45 | request.on('error', function (error) { 46 | 47 | callback(error); 48 | }); 49 | 50 | request.write(body); 51 | request.end(); 52 | }; 53 | 54 | var doVwsRequest = function (request, callback) { 55 | 56 | request.accessKey = options.accessKey; 57 | request.secretKey = options.secretKey; 58 | request.timestamp = util.timestamp(); 59 | 60 | var httpsOptions = { 61 | 62 | hostname: vwsHostname, 63 | path: request.path, 64 | method: request.method, 65 | headers: { 66 | 67 | 'Content-Length': Buffer.byteLength(request.body), 68 | 'Content-Type': request.contentTypeHeader || request.type, 69 | 'Authorization': util.createAuthorization(request), 70 | 'Date': request.timestamp 71 | } 72 | 73 | }; 74 | 75 | doHttpsRequest(httpsOptions, request.body, callback); 76 | }; 77 | 78 | var doCloudRecoRequest = function (request, callback) { 79 | 80 | request.accessKey = options.clientAccessKey; 81 | request.secretKey = options.clientSecretKey; 82 | request.timestamp = util.timestamp(); 83 | 84 | var httpsOptions = { 85 | 86 | hostname: cloudRecoHostname, 87 | path: request.path, 88 | method: request.method, 89 | headers: { 90 | 91 | 'Content-Length': Buffer.byteLength(request.body), 92 | 'Content-Type': request.contentTypeHeader || request.type, 93 | 'Authorization': util.createAuthorization(request), 94 | 'Date': request.timestamp 95 | } 96 | 97 | }; 98 | 99 | doHttpsRequest(httpsOptions, request.body, callback); 100 | }; 101 | 102 | var listTargets = function(callback) { 103 | 104 | var request = { 105 | 106 | 'path': '/targets', 107 | 'method': 'GET', 108 | 'type': 'application/json', 109 | 'body': '' 110 | }; 111 | 112 | doVwsRequest(request, callback); 113 | 114 | }; 115 | 116 | var addTarget = function (target, callback) { 117 | 118 | var request = { 119 | 120 | 'path': '/targets', 121 | 'method': 'POST', 122 | 'type': 'application/json', 123 | 'body': JSON.stringify(target) 124 | }; 125 | 126 | doVwsRequest(request, callback); 127 | }; 128 | 129 | var retrieveTarget = function (targetId, callback) { 130 | 131 | var request = { 132 | 133 | 'path': '/targets/' + targetId, 134 | 'method': 'GET', 135 | 'type': 'application/json', 136 | 'body': '' 137 | }; 138 | 139 | doVwsRequest(request, callback); 140 | 141 | }; 142 | 143 | var updateTarget = function (targetId, target, callback) { 144 | 145 | var request = { 146 | 147 | 'path': '/targets/' + targetId, 148 | 'method': 'PUT', 149 | 'type': 'application/json', 150 | 'body': JSON.stringify(target) 151 | }; 152 | 153 | doVwsRequest(request, callback); 154 | }; 155 | 156 | var deleteTarget = function (targetId, callback) { 157 | 158 | var request = { 159 | 160 | 'path': '/targets/' + targetId, 161 | 'method': 'DELETE', 162 | 'type': 'application/json', 163 | 'body': '' 164 | }; 165 | 166 | doVwsRequest(request, callback); 167 | }; 168 | 169 | var checkForDuplicateTargets = function (targetId, callback) { 170 | 171 | var request = { 172 | 173 | 'path': '/duplicates/' + targetId, 174 | 'method': 'GET', 175 | 'type': 'application/json', 176 | 'body': '' 177 | }; 178 | 179 | doVwsRequest(request, callback); 180 | }; 181 | 182 | var cloudRecoQuery = function (binaryImage, max_num_results, callback) { 183 | 184 | var request = { 185 | 186 | 'path': '/v1/query', 187 | 'method': 'POST', 188 | 'type': 'multipart/form-data', 189 | 'body': util.createCloudRecoQueryBody(binaryImage, max_num_results), 190 | 'contentTypeHeader': util.createCloudRecoQueryContentTypeHeader() 191 | }; 192 | 193 | doCloudRecoRequest(request, callback); 194 | }; 195 | 196 | var retrieveTargetSummary = function (targetId, callback) { 197 | 198 | var request = { 199 | 200 | 'path': '/summary/' + targetId, 201 | 'method': 'GET', 202 | 'type': 'application/json', 203 | 'body': '' 204 | }; 205 | 206 | doRequest(request, callback); 207 | }; 208 | 209 | return { 210 | 211 | 'listTargets' : listTargets, 212 | 'addTarget': addTarget, 213 | 'retrieveTarget': retrieveTarget, 214 | 'updateTarget' : updateTarget, 215 | 'deleteTarget' : deleteTarget, 216 | 'checkForDuplicateTargets': checkForDuplicateTargets, 217 | 'cloudRecoQuery': cloudRecoQuery, 218 | 'retrieveTargetSummary':retrieveTargetSummary 219 | }; 220 | 221 | }; 222 | 223 | module.exports = client; 224 | --------------------------------------------------------------------------------