diff --git a/addons/api/addon/models/session.js b/addons/api/addon/models/session.js index 8c81b8a5a..7ec468630 100644 --- a/addons/api/addon/models/session.js +++ b/addons/api/addon/models/session.js @@ -2,14 +2,88 @@ import GeneratedSessionModel from '../generated/models/session'; import { computed } from '@ember/object'; import { equal } from '@ember/object/computed'; import { tracked } from '@glimmer/tracking'; +import { A } from '@ember/array'; +import { typeOf } from '@ember/utils'; + +/** + * + */ +class SessionCredential { + // =classes + + /** + * + */ + static Library = class Library { + id; + name; + description; + type; + + constructor(id, name, description, type) { + this.id = id; + this.name = name; + this.description = description; + this.type = type; + } + }; + + /** + * + */ + static SecretItem = class SecretItem { + key; + value; + + constructor(key, value) { + this.key = key; + this.value = value; + } + }; + + // =attributes + rawCredential; + library; + purpose; + #rawSecretValue; + + /** + * The credential secret as an array of key/value objects. + * @type {SessionCredential.SecretItem[]} + */ + get secrets() { + if (typeOf(this.#rawSecretValue) === 'object') { + return Object.keys(this.#rawSecretValue).map( + (key) => + new SessionCredential.SecretItem(key, this.#rawSecretValue[key]) + ); + } else { + return [new SessionCredential.SecretItem('secret', this.#rawSecretValue)]; + } + } + + // =methods + + constructor(cred) { + const { id, name, description, type } = cred.credential_library; + this.library = new SessionCredential.Library(id, name, description, type); + this.#rawSecretValue = cred.secret; + this.rawCredential = cred; + this.purpose = cred.purpose; + } +} export default class SessionModel extends GeneratedSessionModel { // =attributes + // These transient attributes are used for values that come from the CLI + // `connect` command as triggered by Desktop. These attributes represent + // transient read-only values. @tracked acknowledged; @tracked started_desktop_client; @tracked proxy_address; @tracked proxy_port; + credentials = A(); @equal('status', 'active') isActive; @equal('status', 'pending') isPending; @@ -43,6 +117,13 @@ export default class SessionModel extends GeneratedSessionModel { // =methods + /** + * + */ + addCredential(cred) { + this.credentials.pushObject(new SessionCredential(cred)); + } + /** * Cancels the session via the `cancel` method. * See serializer and adapter for more information. diff --git a/addons/api/mirage/scenarios/ipc.js b/addons/api/mirage/scenarios/ipc.js index f8fdf6fde..86ffbe83e 100644 --- a/addons/api/mirage/scenarios/ipc.js +++ b/addons/api/mirage/scenarios/ipc.js @@ -58,6 +58,60 @@ export default function initializeMockIPC(server) { port: datatype.number(), protocol: type, session_id: newSession.id, + credentials: [ + { + credential_library: { + id: 'clvlt_4cvscMTl0N', + name: 'Library Name', + description: 'Library Description', + credential_store_id: 'csvlt_Q1HFGt7Jpm', + type: 'vault', + }, + purpose: 'application', + secret: 'just-a-random-string', + }, + { + credential_library: { + id: 'clvlt_4cvscMTl0N', + name: 'Library Name', + description: 'Library Description', + credential_store_id: 'csvlt_Q1HFGt7Jpm', + type: 'vault', + }, + purpose: 'ingress', + secret: { + key1: 'value 1', + key2: true, + key3: 'test', + }, + }, + { + credential_library: { + id: 'clvlt_9KWscxpcY7', + name: 'Library Name', + description: 'Library Description', + credential_store_id: 'csvlt_Q1HFGt7Jpm', + type: 'vault', + }, + purpose: 'application', + secret: 'just-a-random-string', + }, + { + credential_library: { + id: 'clvlt_9KWscxpcY7', + name: 'Library Name', + description: 'Library Description', + credential_store_id: 'csvlt_Q1HFGt7Jpm', + type: 'vault', + }, + purpose: 'egress', + secret: { + key1: 'value 1', + key2: true, + key3: 'test', + }, + }, + ], }; } diff --git a/addons/core/translations/form/en-us.yaml b/addons/core/translations/form/en-us.yaml index 5d2a58567..ba8252614 100644 --- a/addons/core/translations/form/en-us.yaml +++ b/addons/core/translations/form/en-us.yaml @@ -108,3 +108,7 @@ email: label: Email full_name: label: Full Name +key: + label: Key +value: + label: Value diff --git a/addons/core/translations/resources/en-us.yaml b/addons/core/translations/resources/en-us.yaml index 888cb980b..dd7ea9359 100644 --- a/addons/core/translations/resources/en-us.yaml +++ b/addons/core/translations/resources/en-us.yaml @@ -147,6 +147,17 @@ session: description: No active sessions available to display yet. actions: connect: Connect + credential: + title: Credential + title_plural: Credentials + secret: + label: Secret + credential_library: + title: Credential Library + actions: + raw-api: + show: View raw API output + hide: Hide raw API output org: title: Org title_plural: Orgs @@ -256,3 +267,4 @@ target: add: title: Add Host Sets description: Select host sets to assign to this target. + secret: ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ ■ diff --git a/ui/desktop/app/components/hidden-secret/index.hbs b/ui/desktop/app/components/hidden-secret/index.hbs index 4061f42e9..a28042fd6 100644 --- a/ui/desktop/app/components/hidden-secret/index.hbs +++ b/ui/desktop/app/components/hidden-secret/index.hbs @@ -1,5 +1,4 @@
- {{! TODO: The span wrap within a div because later we will add the toggle secret icon/button}} session.addCredential(cred)); + } } catch(e) { this.confirm.confirm(e.message, { isConnectError: true }) // Retry diff --git a/ui/desktop/app/styles/app.scss b/ui/desktop/app/styles/app.scss index d46233c9f..5e1042934 100644 --- a/ui/desktop/app/styles/app.scss +++ b/ui/desktop/app/styles/app.scss @@ -395,19 +395,30 @@ $chevron-down: url("data:image/svg+xml;utf-8, <:body> -

{{t 'resources.target.messages.proxy_url.title'}} - ({{t 'resources.target.types.tcp'}})

+

+ {{t 'resources.target.messages.proxy_url.title'}} + ({{t 'resources.target.types.tcp'}}) +

- {{session.proxy_address}}:{{session.proxy_port}} + {{session.proxy}}

- {{!-- + {{#if session.credentials}} + -

Credentials

+

{{t 'resources.session.credential.title_plural'}}

- - <:header> - - - - <:body> - - - - Key - Value - - - - - foo - Value - - - ttl - Test - - - - - <:footer> - -
-                    
-  {
-    "auth": null,
-    "lease_duration": 3600,
-    "lease_id": "",
-    "renewable": false
-  }
-                    
-                  
-
- -
--}} - + <:header> + + + <:key>{{t 'form.id.label'}} + <:value> + + {{credential.library.id}} + + + + + <:key>{{t 'form.type.label'}} + <:value>{{credential.library.type}} + + {{#if credential.library.name}} + + <:key>{{t 'form.name.label'}} + <:value>{{credential.library.name}} + + {{/if}} + {{#if credential.library.description}} + + <:key>{{t 'form.description.label'}} + <:value>{{credential.library.description}} + + {{/if}} + + + <:body> + {{#if credential.secrets}} + + + + {{t + 'form.key.label' + }} + {{t + 'form.value.label' + }} + + + + {{#each credential.secrets as |secret|}} + + {{secret.key}} + + + {{secret.value}} + + + + {{/each}} + + + {{/if}} + + <:footer> + +
{{raw-json credential.rawCredential}}
+
+ + + {{/each}} + {{/if}} <:footer>
@@ -93,15 +144,6 @@ {{t 'actions.close'}}
-
- {{! - - }} -
{{/unless}} diff --git a/ui/desktop/electron-app/config/cli.js b/ui/desktop/electron-app/config/cli.js index 22092de64..9af356e9e 100644 --- a/ui/desktop/electron-app/config/cli.js +++ b/ui/desktop/electron-app/config/cli.js @@ -48,6 +48,10 @@ const extract = (artifactPath, destination) => { module.exports = { setup: async () => { + if (process.env.BYPASS_CLI_SETUP) { + console.warn('WARNING: Bypassing cli setup'); + return; + } const artifactPath = await downloadArtifact(artifactVersion); await extract(artifactPath, artifactDestination); } diff --git a/ui/desktop/tests/integration/helpers/raw-json-test.js b/ui/desktop/tests/integration/helpers/raw-json-test.js new file mode 100644 index 000000000..34574a8a5 --- /dev/null +++ b/ui/desktop/tests/integration/helpers/raw-json-test.js @@ -0,0 +1,19 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Helper | raw-json', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + this.set('inputValue', {}); + await render(hbs`{{raw-json inputValue}}`); + assert.equal(this.element.textContent.trim(), '{}'); + this.set('inputValue', { key: 'value', nestedKey: { key: 'value' } }); + assert.equal( + this.element.textContent.trim(), + `{\n "key": "value",\n "nestedKey": {\n "key": "value"\n }\n}` + ); + }); +}); diff --git a/yarn.lock b/yarn.lock index ac5c10ef8..2c78436b9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3671,7 +3671,7 @@ agent-base@4, agent-base@^4.3.0: dependencies: es6-promisify "^5.0.0" -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -6360,9 +6360,9 @@ caniuse-api@^3.0.0: lodash.uniq "^4.5.0" caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001157, caniuse-lite@^1.0.30001219: - version "1.0.30001235" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz#ad5ca75bc5a1f7b12df79ad806d715a43a5ac4ed" - integrity sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A== + version "1.0.30001239" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001239.tgz#66e8669985bb2cb84ccb10f68c25ce6dd3e4d2b8" + integrity sha512-cyBkXJDMeI4wthy8xJ2FvDU6+0dtcZSJW3voUF8+e9f1bBeuvyZfc3PNbkOETyhbR+dGCPzn9E7MA3iwzusOhQ== capture-exit@^2.0.0: version "2.0.0" @@ -15671,7 +15671,16 @@ npm-package-arg@^7.0.0: semver "^5.6.0" validate-npm-package-name "^3.0.0" -npm-package-arg@^8.0.0, npm-package-arg@^8.1.0: +npm-package-arg@^8.0.0: + version "8.1.5" + resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" + integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== + dependencies: + hosted-git-info "^4.0.1" + semver "^7.3.4" + validate-npm-package-name "^3.0.0" + +npm-package-arg@^8.1.0: version "8.1.4" resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.4.tgz#8001cdbc4363997b8ef6c6cf7aaf543c5805879d" integrity sha512-xLokoCFqj/rPdr3LvcdDL6Kj6ipXGEDHD/QGpzwU6/pibYUOXmp5DBmg76yukFyx4ZDbrXNOTn+BPyd8TD4Jlw== @@ -19098,11 +19107,11 @@ socks-proxy-agent@^4.0.0: socks "~2.3.2" socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== + version "5.0.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" + integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== dependencies: - agent-base "6" + agent-base "^6.0.2" debug "4" socks "^2.3.3" @@ -21634,9 +21643,9 @@ write@^0.2.1: mkdirp "^0.5.1" ws@^7.4.5, ws@^7.4.6, ws@~7.4.2: - version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + version "7.5.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.0.tgz#0033bafea031fb9df041b2026fc72a571ca44691" + integrity sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw== x-is-string@^0.1.0: version "0.1.0" @@ -21744,9 +21753,9 @@ yaml@^1.10.0, yaml@^1.7.2: integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yargs-parser@20.2.4, yargs-parser@^15.0.1, yargs-parser@^18.1.2, yargs-parser@^20.0.0, yargs-parser@^20.2.2, yargs-parser@^20.2.3, yargs-parser@^7.0.0, yargs-parser@^9.0.2, yargs-parser@~20.2.7: - version "20.2.7" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" - integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== yargs-unparser@2.0.0: version "2.0.0"