UNPKG

8.79 kBJavaScriptView Raw
1/*
2* register.js
3*
4* setup script to register an App at the Registrar and any provided resource servers
5*
6* Copyright (C) Province of British Columbia, 2013
7*/
8
9var fs = require('fs')
10 , async = require('async')
11 , urlParse = require('url').parse
12 , jwt = require('../lib/jwt')
13 , fetch = require('../lib/requestjar').fetch // wrapper around request module that deals with cookies across hosts
14
15// TBD - change defaults to httpS when certs are available XXXXXXXX
16
17
18function terminate( message ) {
19 console.error('error: '+message)
20 process.exit( 1 )
21}
22
23var CONFIG_FILE = process.argv[2]
24
25if (!CONFIG_FILE) terminate('register.js needs a config file')
26if (!fs.existsSync(CONFIG_FILE)) terminate('does not look like '+CONFIG_FILE+'is a file')
27var data = fs.readFileSync( CONFIG_FILE )
28try {
29 var config = JSON.parse(data)
30}
31catch (e) {
32 terminate('Error parsing "'+CONFIG_FILE+'"\n'+e)
33}
34
35var VAULT_FILE = process.cwd() + '/vault.json'
36
37// build our list of known resources
38var provinces =
39 ['ab', 'bc', 'mb', 'nb', 'nl', 'ns', 'nt', 'nu', 'on', 'pe', 'qc', 'sk', 'yt']
40var knownResources =
41 { 'si.a2p3.net': true
42 , 'people.a2p3.net': true
43 , 'health.a2p3.net': true
44 , 'email.a2p3.net': true
45 }
46provinces.forEach( function ( province ) {
47 knownResources['people.'+province+'.a2p3.net'] = true
48 knownResources['health.'+province+'.a2p3.net'] = true
49})
50
51if (config.device == "SET_THIS_TO_THE_DEVICE_VALUE_FROM_YOUR_CLI_AGENT")
52 terminate('\n\nNot so good at following directions eh?\nGet a "device" value from a CLI at http://setup.a2p3.net and put it into config.json\n')
53if (!config.appID) terminate('"appID" is required')
54if (!config.name) terminate('"name" is required')
55if (!config.device) terminate('"device" is required')
56
57
58// congig.json parameters used when testing against locally running A2P3 environment
59config.registrar = config.registrar || 'registrar.a2p3.net'
60config.ix = config.ix || 'ix.a2p3.net'
61config.registrarURL = config.registrarURL || 'http://registrar.a2p3.net'
62config.setupURL = config.setupURL || 'http://setup.a2p3.net'
63config.protocol = config.protocol || 'http'
64if (config.protocol == 'https') {
65 config.port = config.port || '443'
66 config.port = ( config.port == '443' ) ? '' : ':'+config.port
67} else { // assume it is 'http'
68 config.port = config.port || '80'
69 config.port = ( config.port == '80' ) ? '' : ':'+config.port
70}
71
72config.resources = config.resources || []
73
74var resourceURL = {}
75resourceURL[config.registrar] = config.registrarURL
76
77// build URLs and delete any resource servers we don't understand
78config.resources.forEach( function ( rs ) {
79 if ( knownResources[rs] )
80 resourceURL[rs] = config.protocol + '://' + rs + config.port
81 else
82 console.error('Ignoring unknown resource:"'+rs+'"')
83})
84
85var vault = {}
86 , tasks = []
87
88//globals we keep between steps
89// we are processing everything sequentially, so this works
90var agentRequest
91 , jws
92 , ixToken
93
94function addKeyTasks ( rs ) {
95 tasks.push( function getAgentRequest ( done ) {
96 console.log(rs,'processing')
97 console.log('\tGetting Agent Request from',resourceURL[rs])
98 var options =
99 { url: resourceURL[rs] + '/login'
100 , method: 'GET'
101 , qs: { json: true }
102 , followRedirect: false
103 }
104 fetch( options, function ( e, response, body ) {
105 var r = null
106 if ( e ) return done( e )
107 if ( response.statusCode != 200 && response.statusCode != 302 )
108 return done('"'+rs+'" returned '+response.statusCode)
109 try {
110 r = JSON.parse( body )
111 }
112 catch (e) {
113 return done( e )
114 }
115 if (!r || !r.result || !r.result.request)
116 return done('Did not expect"'+body+'"')
117 // save Agent Request and parse it for next call
118 var agentUrl = r.result.request
119 var u = urlParse( agentUrl, true )
120 agentRequest = u.query.request
121 jws = new jwt.Parse( agentRequest )
122 done( null )
123 })
124 })
125 tasks.push( function getIXToken ( done ) {
126 console.log('\tGetting IX Token from',config.setupURL)
127 var options =
128 { url: config.setupURL + '/token'
129 , method: 'POST'
130 , json:
131 { device: config.device
132 , sar: jws.signature
133 , auth: { passcode: true, authorization: true }
134 }
135 }
136 fetch( options, function ( e, response, json ) {
137 if ( e ) return done( e )
138 if ( response.statusCode != 200 && response.statusCode != 302 )
139 return done('"'+rs+'" returned '+response.statusCode)
140 if (json.error)
141 return done("Received error:"+JSON.stringify(json.error))
142 if (!json || !json.result || !json.result.token)
143 return done('Did not expect"'+JSON.stringify(json)+'"')
144 // save code for next step
145 ixToken = json.result.token
146 done( null )
147 })
148 })
149 tasks.push( function login ( done ) {
150 console.log('\tLogging into',resourceURL[rs])
151 var options =
152 { url: jws.payload['request.a2p3.org'].returnURL
153 , method: 'GET'
154 , qs: { token: ixToken }
155 , followRedirect: false
156 }
157 fetch( options, function ( e, response ) {
158 if ( e ) return done( e )
159 if ( response.statusCode != 304 && response.statusCode != 302 )
160 return done('"'+rs+'" returned '+response.statusCode)
161 if ( !response.headers || !response.headers.location ||
162 response.headers.location != '/dashboard')
163 return done('Was sent not redirected to /dashboard')
164 done( null )
165 })
166 })
167 tasks.push( function fetchDashboard ( done ) {
168 console.log('\tGetting /dashboard from',resourceURL[rs])
169 var options =
170 { url: resourceURL[rs] + '/dashboard'
171 , method: 'GET'
172 , followRedirect: false
173 }
174 fetch( options, function ( e, response ) {
175 if ( e ) return done( e )
176 if ( response.statusCode != 200 )
177 return done('"'+rs+'" returned '+response.statusCode)
178 done( null )
179 })
180 })
181 tasks.push( function getKeys ( done ) {
182 // frist we see if we can read existing keys in case the app was already registered
183 console.log('\tGetting keys at '+rs)
184 console.log('\tChecking if "'+config.appID+'" registered at "'+rs+'"')
185 var options =
186 { url: resourceURL[rs] + '/dashboard/getkey'
187 , form: { id: config.appID }
188 , method: 'POST'
189 }
190 fetch( options, function ( e, response, body ) {
191 var r = null
192 if ( e ) return done( e )
193 if ( response.statusCode != 200 )
194 return done('"'+rs+'" returned '+response.statusCode)
195 try {
196 r = JSON.parse( body )
197 }
198 catch (e) {
199 return done( e )
200 }
201 if (!r)
202 return done('Did not expect"'+body+'"')
203 if (!r.error) {
204 if (r.result && r.result.key) { // regular resource or Registrar
205 vault[rs] = r.result.key
206 if (rs == config.registrar) vault[config.ix] = r.result.key
207 } else { // standardized resource
208 Object.keys(r.result).forEach( function ( host ) {
209 vault[host] = r.result[host]
210 })
211 }
212 done( null )
213 } else { // we got an error, try registering the app
214 console.log('\tRegistering "'+config.appID+'" at "'+rs+'"')
215 var options =
216 { url: resourceURL[rs] + '/dashboard/new/app'
217 , form: { id: config.appID }
218 , method: 'POST'
219 }
220 if (rs == config.registrar) options.form.name = config.name
221 fetch( options, function ( e, response, body ) {
222 var r = null
223 if ( e ) return done( e )
224 if ( response.statusCode != 200 )
225 return done('"'+rs+'" returned '+response.statusCode)
226 try {
227 r = JSON.parse( body )
228 }
229 catch (e) {
230 return done( e )
231 }
232 if (!r || !r.result)
233 return done('Did not expect"'+body+'"')
234 if (r.result.key) { // regular resource or Registrar
235 vault[rs] = r.result.key
236 if (rs == config.registrar) vault[config.ix] = r.result.key
237 } else { // standardized resource
238 Object.keys(r.result).forEach( function ( host ) {
239 vault[host] = r.result[host]
240 })
241 }
242 done( null )
243 })
244 }
245 })
246 })
247}
248
249// add tasks for Registrar and each RS
250addKeyTasks( config.registrar ) // registrar needs to be added first
251Object.keys( resourceURL ).forEach( function (rs) {
252 if (rs != config.registrar)
253 addKeyTasks( rs )
254})
255
256
257// Add task to write out the resulting vault
258tasks.push( function writeVault() {
259 var data = JSON.stringify( vault )
260 console.log('... writing "vault.json"')
261 fs.writeFileSync( VAULT_FILE, data)
262})
263
264// go execute all our tasks now!
265async.series( tasks, function (error) {
266 if (error) {
267 console.log( error )
268 process.exit(1)
269 }
270})
\No newline at end of file