index.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.Integration = exports.EnterpriseIntegrationConfig = void 0;
  4. const tslib_1 = require("tslib");
  5. const cli_framework_1 = require("@ionic/cli-framework");
  6. const cli_framework_prompts_1 = require("@ionic/cli-framework-prompts");
  7. const utils_fs_1 = require("@ionic/utils-fs");
  8. const lodash = tslib_1.__importStar(require("lodash"));
  9. const path = tslib_1.__importStar(require("path"));
  10. const __1 = require("../");
  11. const guards_1 = require("../../../guards");
  12. const color_1 = require("../../color");
  13. const errors_1 = require("../../errors");
  14. const CHOICE_CREATE_NEW_APP = 'createNewApp';
  15. class EnterpriseIntegrationConfig extends cli_framework_1.BaseConfig {
  16. provideDefaults(c) {
  17. return {};
  18. }
  19. }
  20. exports.EnterpriseIntegrationConfig = EnterpriseIntegrationConfig;
  21. class Integration extends __1.BaseIntegration {
  22. constructor() {
  23. super(...arguments);
  24. this.name = 'enterprise';
  25. this.summary = 'Ionic Enterprise Edition provides premier native solutions, UI, & support for companies building cross-platform apps.';
  26. this.archiveUrl = undefined;
  27. }
  28. async enable(config) {
  29. const baseConfig = config && config.root ? { root: config.root } : undefined;
  30. await this.updateNPMRC();
  31. return super.enable(baseConfig);
  32. }
  33. async add(details) {
  34. let productKey = this.config.get('productKey');
  35. let appId = this.config.get('appId');
  36. if (details.enableArgs) {
  37. const parsedArgs = (0, cli_framework_1.parseArgs)(details.enableArgs, { string: ['app-id', 'key'] });
  38. appId = parsedArgs['app-id'];
  39. productKey = parsedArgs['key'];
  40. }
  41. if (!productKey) {
  42. productKey = await this.e.prompt({
  43. type: 'input',
  44. name: 'product-key',
  45. message: 'Please enter your product key:',
  46. });
  47. }
  48. const keyInfo = await this.validatePK(productKey, appId);
  49. for (const entry of lodash.entries(keyInfo)) {
  50. const [key, value] = entry;
  51. this.config.set(key, value);
  52. }
  53. return super.add(details);
  54. }
  55. async validatePK(pk, appId) {
  56. let key = await this.getPK(pk);
  57. if (!key.app || appId) {
  58. if (!key.org) {
  59. // temporary error until we make possible to link the key to an app for personal accounts
  60. throw new errors_1.FatalException('No App attached to key. Please contact support@ionic.io');
  61. }
  62. if (!appId) {
  63. appId = await this.chooseAppToLink(key.org);
  64. }
  65. key = await this.registerKey(key, appId);
  66. }
  67. return {
  68. keyId: key.id,
  69. productKey: key.key,
  70. appId: key.app.id,
  71. orgId: key.org ? key.org.id : undefined,
  72. registries: key.registries,
  73. };
  74. }
  75. async chooseAppToLink(org) {
  76. const appClient = await this.getAppClient();
  77. const paginator = appClient.paginate({}, org.id);
  78. const apps = [];
  79. for (const r of paginator) {
  80. const res = await r;
  81. apps.push(...res.data);
  82. }
  83. let appId = await this.chooseApp(apps, org);
  84. if (appId === CHOICE_CREATE_NEW_APP) {
  85. appId = await this.createNewApp(org);
  86. }
  87. return appId;
  88. }
  89. async registerKey(key, appId) {
  90. const token = await this.e.session.getUserToken();
  91. const { req } = await this.e.client.make('PATCH', `/orgs/${key.org.id}/keys/${key.id}`);
  92. req.set('Authorization', `Bearer ${token}`);
  93. req.send({ app_id: appId });
  94. try {
  95. const res = await this.e.client.do(req);
  96. return res.data;
  97. }
  98. catch (e) {
  99. if ((0, guards_1.isSuperAgentError)(e)) {
  100. if (e.response.status === 401 || e.response.status === 403) {
  101. throw new errors_1.FatalException('Authorization Failed. Make sure you\'re logged into the correct account with access to the key. Try logging out and back in again.');
  102. }
  103. const apiErrorMessage = (e.response.body.error && e.response.body.error.message) ? e.response.body.error.message : 'Api Error';
  104. throw new errors_1.FatalException(`Unable to Register Key: ` + apiErrorMessage);
  105. }
  106. else {
  107. throw e;
  108. }
  109. }
  110. }
  111. async getAppClient() {
  112. const { AppClient } = await Promise.resolve().then(() => tslib_1.__importStar(require('../../../lib/app')));
  113. const token = await this.e.session.getUserToken();
  114. return new AppClient(token, this.e);
  115. }
  116. async createNewApp(org) {
  117. const appName = await this.e.prompt({
  118. type: 'input',
  119. name: 'appName',
  120. message: 'Please enter the name of your app:',
  121. });
  122. const appClient = await this.getAppClient();
  123. const newApp = await appClient.create({ org_id: org.id, name: appName });
  124. return newApp.id;
  125. }
  126. async chooseApp(apps, org) {
  127. const { formatName } = await Promise.resolve().then(() => tslib_1.__importStar(require('../../../lib/app')));
  128. const newAppChoice = {
  129. name: (0, color_1.strong)('Create A New App'),
  130. id: CHOICE_CREATE_NEW_APP,
  131. value: CHOICE_CREATE_NEW_APP,
  132. org,
  133. };
  134. const linkedApp = await this.e.prompt({
  135. type: 'list',
  136. name: 'linkedApp',
  137. message: 'This key needs to be registered to an app. Which app would you like to register it to?',
  138. choices: [
  139. ...apps.map(app => ({
  140. name: `${formatName(app)} ${(0, color_1.weak)(`(${app.id})`)}`,
  141. value: app.id,
  142. })),
  143. (0, cli_framework_prompts_1.createPromptChoiceSeparator)(),
  144. newAppChoice,
  145. (0, cli_framework_prompts_1.createPromptChoiceSeparator)(),
  146. ],
  147. });
  148. return linkedApp;
  149. }
  150. async getPK(pk) {
  151. const token = await this.e.session.getUserToken();
  152. const { req } = await this.e.client.make('GET', '/keys/self');
  153. req.set('Authorization', `Bearer ${token}`).set('Product-Key-ID', pk);
  154. try {
  155. const res = await this.e.client.do(req);
  156. return res.data;
  157. }
  158. catch (e) {
  159. if ((0, guards_1.isSuperAgentError)(e)) {
  160. if (e.response.status === 401 || e.response.status === 403) {
  161. throw new errors_1.FatalException('Authorization Failed. Make sure you\'re logged into the correct account with access to the key. Try logging out and back in again.');
  162. }
  163. if (e.response.status === 404) {
  164. throw new errors_1.FatalException('Invalid Product Key');
  165. }
  166. const apiErrorMessage = (e.response.body.error && e.response.body.error.message) ? e.response.body.error.message : 'Api Error';
  167. throw new errors_1.FatalException(`Unable to Add Integration: ` + apiErrorMessage);
  168. }
  169. else {
  170. throw e;
  171. }
  172. }
  173. }
  174. async updateNPMRC() {
  175. const pk = this.config.get('productKey');
  176. const registries = this.config.get('registries');
  177. if (!pk || !registries) {
  178. throw new errors_1.FatalException('Enterprise config invalid');
  179. }
  180. let npmrc = '';
  181. try {
  182. npmrc = await (0, utils_fs_1.readFile)(path.join(this.e.project.directory, '.npmrc'), 'utf8');
  183. }
  184. catch (e) {
  185. if (!e.message.includes('ENOENT')) {
  186. throw e;
  187. }
  188. }
  189. for (const entry of registries) {
  190. const [scope, url] = entry.split(';');
  191. const urlNoProt = url.split(':').splice(1).join(':');
  192. const scopeRegex = new RegExp(`${scope}:registry.*\\n?`, 'g');
  193. const urlRegex = new RegExp(`${urlNoProt}:_authToken.*\\n?`, 'g');
  194. const newScope = `${scope}:registry=${url}\n`;
  195. const newUrl = `${urlNoProt}:_authToken=${pk}\n`;
  196. if (npmrc.match(scopeRegex)) {
  197. npmrc = npmrc.replace(scopeRegex, newScope);
  198. }
  199. else {
  200. npmrc += newScope;
  201. }
  202. if (npmrc.match(urlRegex)) {
  203. npmrc = npmrc.replace(urlRegex, newUrl);
  204. }
  205. else {
  206. npmrc += newUrl;
  207. }
  208. }
  209. await (0, utils_fs_1.writeFile)(path.join(this.e.project.directory, `.npmrc`), npmrc, { encoding: 'utf8' });
  210. }
  211. get config() {
  212. return new EnterpriseIntegrationConfig(this.e.project.filePath, { pathPrefix: [...this.e.project.pathPrefix, 'integrations', this.name] });
  213. }
  214. }
  215. exports.Integration = Integration;