UNPKG

6.38 kBJavaScriptView Raw
1var async = require('async');
2var _ = require('lodash');
3var fs = require('fs');
4var api = require('./api');
5var log = require('./log');
6var parseUrl = require('url').parse;
7var manifest = require('./manifest');
8var debug = require('debug')('4front:cli:init');
9var inquirer = require('inquirer');
10
11require('simple-errors');
12
13// Initialization routine that runs before any CLI command
14module.exports = function(program, options, callback) {
15 log.debug("initiliazing CLI");
16
17 _.defaults(options, {
18 requireAuth: false,
19 loadManifest: false,
20 loadVirtualApp: false
21 });
22
23 var initTasks = [];
24
25 initTasks.push(ensure4frontConfigExists);
26
27 if (options.requireAuth === true) {
28 initTasks.push(ensureProfileExists);
29 initTasks.push(selectProfile);
30 initTasks.push(checkForJwt);
31 initTasks.push(promptForCredentials);
32 initTasks.push(updateProfileConfig);
33 }
34
35 if (options.loadManifest === true) {
36 initTasks.push(loadManifest);
37 }
38
39 if (options.loadManifest && options.loadVirtualApp) {
40 initTasks.push(loadVirtualApp);
41 }
42
43 async.series(initTasks, callback);
44
45 function ensureProfileExists(cb) {
46 debug("prompt for profile");
47
48 // If there is already at least one configured profile
49 if (_.isEmpty(program.globalConfig.profiles) === false)
50 return cb();
51
52 // Run the initalization flow
53 log.messageBox("No 4front instances have been configured. \n" +
54 "Please enter the URL of your instance:");
55
56 debug("no configured profiles, prompt for one");
57 inquirer.prompt([{
58 type: "input",
59 name: "endpoint",
60 message: "Endpoint URL:"
61 }, {
62 type: "input",
63 name: "identityProvider",
64 message: "Identity provider:"
65 }], function(answers) {
66 // Make the new instance the default
67 program.globalConfig.profiles = [{
68 endpoint: answers.endpoint,
69 name: 'default',
70 default: true,
71 identityProvider: answers.identityProvider
72 }];
73
74 cb();
75 });
76 }
77
78 // Prompt for which 4front profile to use
79 function selectProfile(cb) {
80 if (program.profile) {
81 program.profile = _.find(program.globalConfig.profiles, {
82 name: program.profile
83 });
84 }
85
86 // Next check if there is an environment variable with the name of a valid profile.
87 var envVarProfile = process.env.FF_PROFILE;
88 if (_.isEmpty(envVarProfile) === false) {
89 program.profile = _.find(program.globalConfig.profiles, {name: envVarProfile});
90 if (!program.profile)
91 cb(new Error("Environment variable FF_PROFILE refers to to an invalid 4front profile."));
92 }
93
94 // If no selectedProfile, try finding the default one.
95 if (!program.profile)
96 program.profile = _.find(program.globalConfig.profiles, {
97 default: true
98 }) || program.globalConfig.profiles[0];
99
100 var endpointUrl = parseUrl(program.profile.endpoint);
101 program.virtualHost = endpointUrl.host;
102
103 debug("using profile: %o", _.pick(program.profile, 'name', 'url'));
104
105 cb();
106 }
107
108 // Check for an existing JWT in the config
109 function checkForJwt(cb) {
110 debug("check for existing jwt");
111
112 // See if we have a login token
113 if (_.isObject(program.profile.jwt) === false)
114 return cb();
115
116 // If force new login, clear out any existing jwt.
117 if (options.forceLogin) {
118 program.profile.jwt = null;
119 return cb();
120 }
121
122 // If the JWT is expired, force user to login again.
123 if (_.isNumber(program.profile.jwt.expires) === false ||
124 Date.now() > program.profile.jwt.expires) {
125 program.profile.jwt = null;
126 }
127
128 cb();
129 }
130
131 function promptForCredentials(cb) {
132 // If we already have a valid JWT, don't force user
133 // to login again.
134 if (program.profile.jwt) {
135 debug("using existing jwt");
136 return cb();
137 }
138
139 debug("prompt for credentials");
140
141 // Prompt for login
142 inquirer.prompt([{
143 type: 'input',
144 name: 'username',
145 message: 'Username:',
146 }, {
147 type: 'password',
148 name: 'password',
149 message: 'Password:'
150 }], function(answers) {
151 answers.identityProvider = program.profile.identityProvider;
152 // Make the api login call.
153 var apiOptions = {
154 method: 'POST',
155 path: '/profile/login',
156 json: answers,
157 authenticate: false
158 };
159
160 api(program, apiOptions, function(err, user) {
161 if (err) return cb(err);
162
163 debug("setting jwt for profile %s: %s", program.profile.name, JSON.stringify(user.jwt));
164
165 // Write the JWT to the configFile for future logins
166 program.profile.jwt = user.jwt;
167 cb();
168 });
169 });
170 }
171
172 function updateProfileConfig(cb) {
173 debug("writing to %s", program.globalConfigPath);
174 var configJson = JSON.stringify(program.globalConfig, null, 2);
175 fs.writeFile(program.globalConfigPath, configJson, cb);
176 }
177
178 function loadManifest(cb) {
179 log.debug("loading virtual app config from package.json");
180
181 manifest.load(program, function(err, config) {
182 if (err) return cb(err);
183
184 program.virtualAppManifest = config;
185 cb();
186 });
187 }
188
189 function loadVirtualApp(cb) {
190 if (!program.virtualAppManifest)
191 return cb();
192
193 log.debug("invoking api to fetch the virtual app");
194 api(program, {method: 'GET', path: '/apps/' + program.virtualAppManifest.appId}, function(err, app) {
195 if (err) return cb(err);
196 if (!app)
197 return cb("Application " + program.virtualAppManifest.appId + " could not be found.");
198
199 debug("virtual app loaded from API");
200 program.virtualApp = app;
201 cb();
202 });
203 }
204
205 function ensure4frontConfigExists(cb) {
206 fs.exists(program.globalConfigPath, function(exists) {
207 if (!exists)
208 return createEmptyConfig();
209
210 // The file exists, now make sure it is valid JSON.
211 fs.readFile(program.globalConfigPath, function(err, data) {
212 if (err) return cb(err);
213
214 try {
215 program.globalConfig = JSON.parse(data.toString());
216 }
217 catch (jsonErr) {
218 debug("Config file %s is corrupt", program.globalConfigPath);
219 return createEmptyConfig();
220 }
221 cb();
222 });
223 });
224
225 function createEmptyConfig() {
226 program.globalConfig = {profiles: []};
227
228 fs.writeFile(program.globalConfigPath,
229 JSON.stringify(program.globalConfig, null, 2), cb);
230 }
231 }
232};