@rancher/shell 3.0.5-rc.9 → 3.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (37) hide show
  1. package/assets/translations/en-us.yaml +11 -5
  2. package/components/PodSecurityAdmission.vue +2 -0
  3. package/components/form/ProjectMemberEditor.vue +2 -0
  4. package/components/nav/Header.vue +6 -5
  5. package/config/store.js +2 -0
  6. package/dialog/SloDialog.vue +1 -1
  7. package/edit/auth/oidc.vue +106 -6
  8. package/edit/auth/saml.vue +5 -5
  9. package/edit/provisioning.cattle.io.cluster/tabs/AddOnAdditionalManifest.vue +1 -0
  10. package/edit/provisioning.cattle.io.cluster/tabs/AddOnConfig.vue +1 -0
  11. package/edit/provisioning.cattle.io.cluster/tabs/Basics.vue +1 -0
  12. package/edit/provisioning.cattle.io.cluster/tabs/etcd/S3Config.vue +1 -0
  13. package/edit/provisioning.cattle.io.cluster/tabs/registries/index.vue +2 -0
  14. package/edit/provisioning.cattle.io.cluster/tabs/upgrade/DrainOptions.vue +6 -0
  15. package/initialize/install-plugins.js +1 -3
  16. package/mixins/__tests__/auth-config.test.ts +4 -6
  17. package/mixins/__tests__/chart.test.ts +1 -1
  18. package/mixins/auth-config.js +33 -10
  19. package/mixins/chart.js +1 -1
  20. package/models/management.cattle.io.cluster.js +1 -1
  21. package/models/workload.js +1 -1
  22. package/package.json +1 -1
  23. package/pages/auth/login.vue +8 -3
  24. package/pages/auth/logout.vue +6 -5
  25. package/pages/c/_cluster/explorer/tools/__tests__/index.test.ts +1 -1
  26. package/pages/c/_cluster/explorer/tools/index.vue +1 -1
  27. package/plugins/axios.js +3 -2
  28. package/plugins/ember-cookie.js +7 -3
  29. package/plugins/steve/subscribe.js +4 -2
  30. package/scripts/test-plugins-build.sh +0 -1
  31. package/store/__tests__/cookies.test.ts +72 -0
  32. package/store/auth.js +33 -10
  33. package/store/cookies.ts +30 -0
  34. package/store/prefs.js +10 -5
  35. package/types/shell/index.d.ts +2 -11
  36. package/utils/auth.js +1 -1
  37. package/utils/cookie-universal.js +0 -10
@@ -478,6 +478,12 @@ addProjectMemberDialog:
478
478
  title: Add Project Member
479
479
 
480
480
  authConfig:
481
+ slo:
482
+ sloTitle: Log Out behavior
483
+ sloOptions:
484
+ onlyRancher: Log out of Rancher and not {name}
485
+ logoutAll: Log out of Rancher and {name} (includes all other applications registered with {name})
486
+ choose: Allow the user to choose one of the above in an additional log out step
481
487
  accessMode:
482
488
  label: 'Configure who should be able to login and use {vendor}'
483
489
  required: Restrict access to only the authorized users & groups
@@ -627,11 +633,6 @@ authConfig:
627
633
  UID: UID Field
628
634
  adfs: Configure an AD FS account
629
635
  api: '{vendor} API Host'
630
- sloTitle: Log Out behavior
631
- sloOptions:
632
- onlyRancher: Log out of Rancher and not {name}
633
- logoutAll: Log out of Rancher and {name} (includes all other applications registered with {name})
634
- choose: Allow the user to choose one of the above in an additional log out step
635
636
  cert:
636
637
  label: Certificate
637
638
  placeholder: Paste in the certificate, starting with -----BEGIN CERTIFICATE-----
@@ -698,6 +699,9 @@ authConfig:
698
699
  title: Are you sure? This update is irreversible.
699
700
  body: '<p><b>You may need to make some additional changes</b>. Please ensure the Azure AD app has the Directory.Read.All <b>Application</b> permission added to Microsoft Graph.<br> If any endpoints were customized while configuring Azure AD authentication in Rancher, they will not be automatically updated. </p>'
700
701
  oidc:
702
+ endSessionEndpoint:
703
+ title: End Session Endpoint
704
+ tooltip: Provider specific URL used for logging a user out of their session
701
705
  genericoidc: Configure an OIDC account
702
706
  keycloakoidc: Configure a Keycloak OIDC account
703
707
  cognito: Configure an Amazon Cognito account
@@ -7566,6 +7570,8 @@ model:
7566
7570
  saml: SAML
7567
7571
  oauth: OAuth
7568
7572
  oidc: OIDC
7573
+ keycloakoidc: Keycloak
7574
+ genericoidc: OIDC provider
7569
7575
  cognito: Amazon Cognito
7570
7576
  name:
7571
7577
  keycloak: Keycloak (SAML)
@@ -222,6 +222,7 @@ export default defineComponent({
222
222
  <Checkbox
223
223
  v-if="!labelsAlwaysActive"
224
224
  v-model:value="psaControl.active"
225
+ :mode="mode"
225
226
  :data-testid="componentTestid + '--psaControl-' + i + '-active'"
226
227
  :label="level"
227
228
  :label-key="`podSecurityAdmission.labels.${ level }`"
@@ -281,6 +282,7 @@ export default defineComponent({
281
282
  <span class="col span-2">
282
283
  <Checkbox
283
284
  v-model:value="psaExemptionsControl.active"
285
+ :mode="mode"
284
286
  :data-testid="componentTestid + '--psaExemptionsControl-' + i + '-active'"
285
287
  :label="dimension"
286
288
  :label-key="`podSecurityAdmission.labels.${ dimension }`"
@@ -286,6 +286,7 @@ export default {
286
286
  <template v-slot:body>
287
287
  <RadioGroup
288
288
  v-model:value="value.permissionGroup"
289
+ :mode="mode"
289
290
  data-testid="permission-options"
290
291
  :options="options"
291
292
  name="permission-group"
@@ -301,6 +302,7 @@ export default {
301
302
  >
302
303
  <Checkbox
303
304
  v-model:value="permission.value"
305
+ :mode="mode"
304
306
  :data-testid="`custom-permission-${i}`"
305
307
  :disabled="permission.locked"
306
308
  class="mb-5"
@@ -29,6 +29,7 @@ import {
29
29
  RcDropdownSeparator,
30
30
  RcDropdownTrigger
31
31
  } from '@components/RcDropdown';
32
+ import { SLO_AUTH_PROVIDERS } from '@shell/store/auth';
32
33
 
33
34
  export default {
34
35
 
@@ -99,10 +100,10 @@ export default {
99
100
  'showWorkspaceSwitcher'
100
101
  ]),
101
102
 
102
- samlAuthProviderEnabled() {
103
+ sloAuthProviderEnabled() {
103
104
  const publicAuthProviders = this.$store.getters['rancher/all']('authProvider');
104
105
 
105
- return publicAuthProviders.find((authProvider) => configType[authProvider.id] === 'saml') || {};
106
+ return publicAuthProviders.find((authProvider) => SLO_AUTH_PROVIDERS.includes(configType[authProvider?.id])) || {};
106
107
  },
107
108
 
108
109
  shouldShowSloLogoutModal() {
@@ -111,7 +112,7 @@ export default {
111
112
  return false;
112
113
  }
113
114
 
114
- const { logoutAllSupported, logoutAllEnabled, logoutAllForced } = this.samlAuthProviderEnabled;
115
+ const { logoutAllSupported, logoutAllEnabled, logoutAllForced } = this.sloAuthProviderEnabled;
115
116
 
116
117
  return logoutAllSupported && logoutAllEnabled && !logoutAllForced;
117
118
  },
@@ -276,8 +277,8 @@ export default {
276
277
  showSloModal() {
277
278
  this.$store.dispatch('management/promptModal', {
278
279
  component: 'SloDialog',
279
- componentProps: { authProvider: this.samlAuthProviderEnabled },
280
- modalWidth: '500px'
280
+ componentProps: { authProvider: this.sloAuthProviderEnabled },
281
+ modalWidth: '600px'
281
282
  });
282
283
  },
283
284
  // Sizes the product area of the header such that it shrinks to ensure the whole header bar can be shown
package/config/store.js CHANGED
@@ -39,6 +39,7 @@ let store = {};
39
39
  resolveStoreModules(require('../store/customisation.js'), 'customisation.js');
40
40
  resolveStoreModules(require('../store/cru-resource.ts'), 'cru-resource.ts');
41
41
  resolveStoreModules(require('../store/notifications.ts'), 'notifications.ts');
42
+ resolveStoreModules(require('../store/cookies.ts'), 'cookies.ts');
42
43
 
43
44
  // If the environment supports hot reloading...
44
45
 
@@ -69,6 +70,7 @@ let store = {};
69
70
  '../store/customisation.js',
70
71
  '../store/cru-resource.ts',
71
72
  '../store/notifications.ts',
73
+ '../store/cookies.ts',
72
74
  ], () => {
73
75
  // Update `root.modules` with the latest definitions.
74
76
  updateModules();
@@ -17,7 +17,7 @@ export default {
17
17
 
18
18
  computed: {
19
19
  name() {
20
- return this.authProvider?.nameDisplay;
20
+ return this.t(`model.authConfig.provider."${ this.authProvider?.id }"`);
21
21
  }
22
22
  },
23
23
 
@@ -1,7 +1,7 @@
1
1
  <script>
2
2
  import Loading from '@shell/components/Loading';
3
3
  import CreateEditView from '@shell/mixins/create-edit-view';
4
- import AuthConfig from '@shell/mixins/auth-config';
4
+ import AuthConfig, { SLO_OPTION_VALUES } from '@shell/mixins/auth-config';
5
5
  import CruResource from '@shell/components/CruResource';
6
6
  import AllowedPrincipals from '@shell/components/auth/AllowedPrincipals';
7
7
  import FileSelector from '@shell/components/form/FileSelector';
@@ -15,6 +15,7 @@ import { RadioGroup } from '@components/Form/Radio';
15
15
  import { Checkbox } from '@components/Form/Checkbox';
16
16
  import { BASE_SCOPES } from '@shell/store/auth';
17
17
  import CopyToClipboardText from '@shell/components/CopyToClipboardText.vue';
18
+ import isUrl from 'is-url';
18
19
 
19
20
  export default {
20
21
  components: {
@@ -33,6 +34,8 @@ export default {
33
34
  CopyToClipboardText,
34
35
  },
35
36
 
37
+ emits: ['validationChanged'],
38
+
36
39
  mixins: [CreateEditView, AuthConfig],
37
40
 
38
41
  data() {
@@ -56,7 +59,8 @@ export default {
56
59
  userInfoEndpoint: null,
57
60
  },
58
61
  // TODO #13457: this is duplicated due wrong format
59
- oidcScope: []
62
+ oidcScope: [],
63
+ SLO_OPTION_VALUES
60
64
  };
61
65
  },
62
66
 
@@ -89,6 +93,11 @@ export default {
89
93
  return false;
90
94
  }
91
95
 
96
+ // make sure that if SLO options are enabled on radio group, field "endSessionEndpoint" is required
97
+ if (this.isLogoutAllSupported && this.sloEndSessionEndpointUiEnabled && (!this.model.endSessionEndpoint || !isUrl(this.model.endSessionEndpoint))) {
98
+ return false;
99
+ }
100
+
92
101
  if (this.isAmazonCognito) {
93
102
  const { issuer } = this.model;
94
103
 
@@ -129,10 +138,36 @@ export default {
129
138
 
130
139
  isAmazonCognito() {
131
140
  return this.model?.id === 'cognito';
141
+ },
142
+
143
+ isLogoutAllSupported() {
144
+ return this.model?.logoutAllSupported;
145
+ },
146
+
147
+ sloOptions() {
148
+ return [
149
+ { value: SLO_OPTION_VALUES.rancher, label: this.t('authConfig.slo.sloOptions.onlyRancher', { name: this.model?.nameDisplay }) },
150
+ { value: SLO_OPTION_VALUES.all, label: this.t('authConfig.slo.sloOptions.logoutAll', { name: this.model?.nameDisplay }) },
151
+ { value: SLO_OPTION_VALUES.both, label: this.t('authConfig.slo.sloOptions.choose') },
152
+ ];
153
+ },
154
+
155
+ sloTypeText() {
156
+ const sloOptionSelected = this.sloOptions.find((item) => item.value === this.sloType);
157
+
158
+ return sloOptionSelected?.label || '';
159
+ },
160
+
161
+ sloEndSessionEndpointUiEnabled() {
162
+ return this.sloType === SLO_OPTION_VALUES.all || this.sloType === SLO_OPTION_VALUES.both;
132
163
  }
133
164
  },
134
165
 
135
166
  watch: {
167
+ fvFormIsValid(newValue) {
168
+ this.$emit('validationChanged', !!newValue);
169
+ },
170
+
136
171
  'oidcUrls.url'() {
137
172
  this.updateEndpoints();
138
173
  },
@@ -166,6 +201,25 @@ export default {
166
201
  if (!old && neu) {
167
202
  this.customEndpoint.value = !this.oidcUrls.url && !!this.model.issuer;
168
203
  }
204
+ },
205
+
206
+ // sloType is defined on shell/mixins/auth-config.js
207
+ sloType(neu) {
208
+ switch (neu) {
209
+ case SLO_OPTION_VALUES.rancher:
210
+ this.model.logoutAllEnabled = false;
211
+ this.model.logoutAllForced = false;
212
+ this.model.endSessionEndpoint = '';
213
+ break;
214
+ case SLO_OPTION_VALUES.all:
215
+ this.model.logoutAllEnabled = true;
216
+ this.model.logoutAllForced = true;
217
+ break;
218
+ case SLO_OPTION_VALUES.both:
219
+ this.model.logoutAllEnabled = true;
220
+ this.model.logoutAllForced = false;
221
+ break;
222
+ }
169
223
  }
170
224
  },
171
225
 
@@ -224,11 +278,19 @@ export default {
224
278
  :edit="goToEdit"
225
279
  >
226
280
  <template #rows>
227
- <tr><td>{{ t(`authConfig.oidc.rancherUrl`) }}: </td><td>{{ model.rancherUrl }}</td></tr>
228
- <tr><td>{{ t(`authConfig.oidc.clientId`) }}: </td><td>{{ model.clientId }}</td></tr>
229
- <tr><td>{{ t(`authConfig.oidc.issuer`) }}: </td><td>{{ model.issuer }}</td></tr>
281
+ <tr><td>{{ t('authConfig.oidc.rancherUrl') }}: </td><td>{{ model.rancherUrl }}</td></tr>
282
+ <tr><td>{{ t('authConfig.oidc.clientId') }}: </td><td>{{ model.clientId }}</td></tr>
283
+ <tr><td>{{ t('authConfig.oidc.issuer') }}: </td><td>{{ model.issuer }}</td></tr>
230
284
  <tr v-if="model.authEndpoint">
231
- <td>{{ t(`authConfig.oidc.authEndpoint`) }}: </td><td>{{ model.authEndpoint }}</td>
285
+ <td>{{ t('authConfig.oidc.authEndpoint') }}: </td><td>{{ model.authEndpoint }}</td>
286
+ </tr>
287
+ <tr v-if="isLogoutAllSupported">
288
+ <td>{{ t('authConfig.slo.sloTitle') }}: </td><td>{{ sloTypeText }}</td>
289
+ </tr>
290
+ <tr v-if="isLogoutAllSupported && sloEndSessionEndpointUiEnabled">
291
+ <td>
292
+ {{ t('authConfig.oidc.endSessionEndpoint.title') }}:
293
+ </td><td>{{ model.endSessionEndpoint }}</td>
232
294
  </tr>
233
295
  </template>
234
296
  </AuthBanner>
@@ -494,6 +556,44 @@ export default {
494
556
  </div>
495
557
  </div>
496
558
  </template>
559
+
560
+ <!-- SLO logout -->
561
+ <div
562
+ v-if="isLogoutAllSupported"
563
+ class="mt-40 mb-20"
564
+ >
565
+ <div class="row">
566
+ <div class="col span-12">
567
+ <h3>{{ t('authConfig.slo.sloTitle') }}</h3>
568
+ </div>
569
+ </div>
570
+ <div class="row">
571
+ <div class="col span-4">
572
+ <RadioGroup
573
+ v-model:value="sloType"
574
+ :mode="mode"
575
+ :options="sloOptions"
576
+ :disabled="!model.logoutAllSupported"
577
+ name="sloTypeRadio"
578
+ />
579
+ </div>
580
+ </div>
581
+ <div
582
+ v-if="sloEndSessionEndpointUiEnabled"
583
+ class="row mt-20"
584
+ >
585
+ <div class="col span-6">
586
+ <LabeledInput
587
+ v-model:value="model.endSessionEndpoint"
588
+ :tooltip="t('authConfig.oidc.endSessionEndpoint.tooltip')"
589
+ :label="t('authConfig.oidc.endSessionEndpoint.title')"
590
+ :mode="mode"
591
+ required
592
+ data-testid="oidc-endSessionEndpoint"
593
+ />
594
+ </div>
595
+ </div>
596
+ </div>
497
597
  </template>
498
598
  </CruResource>
499
599
  </div>
@@ -73,9 +73,9 @@ export default {
73
73
 
74
74
  sloOptions() {
75
75
  return [
76
- { value: SLO_OPTION_VALUES.rancher, label: this.t('authConfig.saml.sloOptions.onlyRancher', { name: this.model?.nameDisplay }) },
77
- { value: SLO_OPTION_VALUES.all, label: this.t('authConfig.saml.sloOptions.logoutAll', { name: this.model?.nameDisplay }) },
78
- { value: SLO_OPTION_VALUES.both, label: this.t('authConfig.saml.sloOptions.choose') },
76
+ { value: SLO_OPTION_VALUES.rancher, label: this.t('authConfig.slo.sloOptions.onlyRancher', { name: this.model?.nameDisplay }) },
77
+ { value: SLO_OPTION_VALUES.all, label: this.t('authConfig.slo.sloOptions.logoutAll', { name: this.model?.nameDisplay }) },
78
+ { value: SLO_OPTION_VALUES.both, label: this.t('authConfig.slo.sloOptions.choose') },
79
79
  ];
80
80
  },
81
81
 
@@ -175,7 +175,7 @@ export default {
175
175
  <tr><td>{{ t(`authConfig.saml.api`) }}: </td><td>{{ model.rancherApiHost }}</td></tr>
176
176
  <tr><td>{{ t(`authConfig.saml.groups`) }}: </td><td>{{ model.groupsField }}</td></tr>
177
177
  <tr v-if="isLogoutAllSupported">
178
- <td>{{ t(`authConfig.saml.sloTitle`) }}: </td><td>{{ sloTypeText }}</td>
178
+ <td>{{ t(`authConfig.slo.sloTitle`) }}: </td><td>{{ sloTypeText }}</td>
179
179
  </tr>
180
180
  </template>
181
181
 
@@ -357,7 +357,7 @@ export default {
357
357
  >
358
358
  <div class="row">
359
359
  <div class="col span-12">
360
- <h3>{{ t('authConfig.saml.sloTitle') }}</h3>
360
+ <h3>{{ t('authConfig.slo.sloTitle') }}</h3>
361
361
  </div>
362
362
  </div>
363
363
  <div class="row">
@@ -41,6 +41,7 @@ export default {
41
41
  <YamlEditor
42
42
  ref="yaml-additional"
43
43
  v-model:value="additionalManifest"
44
+ :mode="mode"
44
45
  :editor-mode="mode === 'view' ? 'VIEW_CODE' : 'EDIT_CODE'"
45
46
  initial-yaml-values="# Additional Manifest YAML"
46
47
  class="yaml-editor"
@@ -99,6 +99,7 @@ export default {
99
99
  ref="yaml-values"
100
100
  data-testid="addon-yaml-editor"
101
101
  :value="initYamlEditor(addonVersion.name)"
102
+ :mode="mode"
102
103
  :scrolling="true"
103
104
  :as-object="true"
104
105
  :editor-mode="mode === 'view' ? 'VIEW_CODE' : 'EDIT_CODE'"
@@ -493,6 +493,7 @@ export default {
493
493
  />
494
494
  <Checkbox
495
495
  :value="showDeprecatedPatchVersions"
496
+ :mode="mode"
496
497
  :label="t('cluster.kubernetesVersion.deprecatedPatches')"
497
498
  :tooltip="t('cluster.kubernetesVersion.deprecatedPatchWarning')"
498
499
  class="patch-version"
@@ -165,6 +165,7 @@ export default {
165
165
  <LabeledInput
166
166
  v-if="!config.skipSSLVerify"
167
167
  v-model:value="config.endpointCA"
168
+ :mode="mode"
168
169
  type="multiline"
169
170
  :label="t('cluster.rke2.etcd.s3config.endpointCA.label')"
170
171
  :placeholder="ccData.defaultEndpointCA"
@@ -78,6 +78,7 @@ export default {
78
78
  <div class="row">
79
79
  <Checkbox
80
80
  :value="showCustomRegistryInput"
81
+ :mode="mode"
81
82
  :label="t('cluster.privateRegistry.label')"
82
83
  data-testid="registries-enable-checkbox"
83
84
  @update:value="$emit('custom-registry-changed', $event)"
@@ -90,6 +91,7 @@ export default {
90
91
  <div class="col span-6">
91
92
  <LabeledInput
92
93
  :value="registryHost"
94
+ :mode="mode"
93
95
  label-key="catalog.chart.registry.custom.inputLabel"
94
96
  placeholder-key="catalog.chart.registry.custom.placeholder"
95
97
  :min-height="30"
@@ -102,6 +102,7 @@ export default {
102
102
  <div class="mt-20">
103
103
  <Checkbox
104
104
  v-model:value="deleteEmptyDirData"
105
+ :mode="mode"
105
106
  label-key="cluster.rke2.drain.deleteEmptyDir.label"
106
107
  tooltip-key="cluster.rke2.drain.deleteEmptyDir.tooltip"
107
108
  @update:value="update"
@@ -110,6 +111,7 @@ export default {
110
111
  <div>
111
112
  <Checkbox
112
113
  v-model:value="force"
114
+ :mode="mode"
113
115
  label="Delete standalone pods"
114
116
  label-key="cluster.rke2.drain.force.label"
115
117
  tooltip="Delete standalone pods which are not managed by a Workload controller (Deployment, Job, etc). Draining will fail if this is not set and there are standalone pods."
@@ -120,12 +122,14 @@ export default {
120
122
  <div>
121
123
  <Checkbox
122
124
  v-model:value="customGracePeriod"
125
+ :mode="mode"
123
126
  label-key="cluster.rke2.drain.gracePeriod.checkboxLabel"
124
127
  @update:value="update"
125
128
  />
126
129
  <UnitInput
127
130
  v-if="customGracePeriod"
128
131
  v-model:value="gracePeriod"
132
+ :mode="mode"
129
133
  label-key="cluster.rke2.drain.gracePeriod.inputLabel"
130
134
  :suffix="t('suffix.seconds', {count: timeout})"
131
135
  class="mb-10"
@@ -135,12 +139,14 @@ export default {
135
139
  <div>
136
140
  <Checkbox
137
141
  v-model:value="customTimeout"
142
+ :mode="mode"
138
143
  label-key="cluster.rke2.drain.timeout.checkboxLabel"
139
144
  @update:value="update"
140
145
  />
141
146
  <UnitInput
142
147
  v-if="customTimeout"
143
148
  v-model:value="timeout"
149
+ :mode="mode"
144
150
  label-key="cluster.rke2.drain.timeout.inputLabel"
145
151
  :suffix="t('suffix.seconds', {count: timeout})"
146
152
  class="drain-timeout"
@@ -12,7 +12,6 @@ import i18n from '@shell/plugins/i18n';
12
12
  import globalFormatters from '@shell/plugins/global-formatters';
13
13
 
14
14
  import axios from '@shell/utils/axios';
15
- import cookieUniversal from '@shell/utils/cookie-universal';
16
15
  import config from '@shell/utils/config';
17
16
  import axiosShell from '@shell/plugins/axios';
18
17
  import codeMirror from '@shell/plugins/codemirror-loader';
@@ -47,7 +46,7 @@ export async function installPlugins(vueApp) {
47
46
  }
48
47
 
49
48
  export async function installInjectedPlugins(app, vueApp) {
50
- const pluginDefinitions = [config, cookieUniversal, axios, plugins, pluginsLoader, axiosShell, intNumber, codeMirror, nuxtClientInit, replaceAll, plugin, steveCreateWorker, emberCookie, internalApiPlugin];
49
+ const pluginDefinitions = [config, axios, plugins, pluginsLoader, axiosShell, intNumber, codeMirror, nuxtClientInit, replaceAll, plugin, steveCreateWorker, emberCookie, internalApiPlugin];
51
50
 
52
51
  const installations = pluginDefinitions.map(async(pluginDefinition) => {
53
52
  if (typeof pluginDefinition === 'function') {
@@ -64,7 +63,6 @@ export async function installInjectedPlugins(app, vueApp) {
64
63
  // If there's any performance reasons this can be done concurrently with all of the installation promises above but I felt it was organizationally better to keep both i18n items together.
65
64
  await app.store.dispatch('i18n/init');
66
65
 
67
- // Order matters here. This is coming after the other plugins specifically so $cookies can be installed. i18n/init relies on prefs/get which relies on $cookies.
68
66
  vueApp.use(i18n, { store: app.store });
69
67
  }
70
68
 
@@ -1,6 +1,7 @@
1
1
  import { mount } from '@vue/test-utils';
2
2
  import authConfigMixin from '@shell/mixins/auth-config';
3
-
3
+ import childHook from '@shell/mixins/child-hook';
4
+ //
4
5
  describe('mixin: authConfigMixin', () => {
5
6
  describe('method: save', () => {
6
7
  const componentMock = (model: any) => ({
@@ -11,10 +12,7 @@ describe('mixin: authConfigMixin', () => {
11
12
  computed: { principal: () => ({ me: {} }) },
12
13
  global: {
13
14
  mocks: {
14
- $store: {
15
- dispatch: () => model,
16
- commit: () => ({ 'auth/loggedInAs': jest.fn() }),
17
- },
15
+ $store: { dispatch: () => model },
18
16
  $route: {
19
17
  params: { id: '123' },
20
18
  query: { mode: 'edit' },
@@ -24,7 +22,7 @@ describe('mixin: authConfigMixin', () => {
24
22
  });
25
23
  const FakeComponent = {
26
24
  render() {},
27
- mixins: [authConfigMixin],
25
+ mixins: [authConfigMixin, childHook],
28
26
  methods: { applyHooks: jest.fn() },
29
27
  };
30
28
 
@@ -235,7 +235,7 @@ describe('chartMixin', () => {
235
235
  expect(wrapper.vm.action).toStrictEqual({
236
236
  name: 'downgrade',
237
237
  tKey: 'downgrade',
238
- icon: 'icon-history',
238
+ icon: 'icon-downgrade-alt',
239
239
  });
240
240
  });
241
241
  });
@@ -1,7 +1,7 @@
1
1
  import { _EDIT } from '@shell/config/query-params';
2
2
  import { NORMAN, MANAGEMENT } from '@shell/config/types';
3
3
  import { AFTER_SAVE_HOOKS, BEFORE_SAVE_HOOKS } from '@shell/mixins/child-hook';
4
- import { BASE_SCOPES } from '@shell/store/auth';
4
+ import { BASE_SCOPES, SLO_AUTH_PROVIDERS } from '@shell/store/auth';
5
5
  import { addObject, findBy } from '@shell/utils/array';
6
6
  import { exceptionToErrorsArray } from '@shell/utils/error';
7
7
  import difference from 'lodash/difference';
@@ -30,6 +30,10 @@ export default {
30
30
  }
31
31
  },
32
32
 
33
+ created() {
34
+ this.registerAfterHook(this.updateAuthProviders, 'force-update-auth-providers');
35
+ },
36
+
33
37
  async fetch() {
34
38
  await this.mixinFetch();
35
39
  },
@@ -88,6 +92,23 @@ export default {
88
92
  },
89
93
 
90
94
  methods: {
95
+ updateAuthProviders() {
96
+ // we need to forcefully re-fetch the authProviders list so that we can update the logout method
97
+ // this is to satisfy the SLO usecase where after setting an auth provider the logout method
98
+ // wasn't being updated because the resource is not watchable
99
+ this.$store.dispatch('auth/getAuthProviders', { force: true });
100
+ },
101
+
102
+ setSloType(selectedModel) {
103
+ if (!selectedModel.logoutAllEnabled && !selectedModel.logoutAllForced) {
104
+ this.sloType = SLO_OPTION_VALUES.rancher;
105
+ } else if (selectedModel.logoutAllEnabled && selectedModel.logoutAllForced) {
106
+ this.sloType = SLO_OPTION_VALUES.all;
107
+ } else if (selectedModel.logoutAllEnabled && !selectedModel.logoutAllForced) {
108
+ this.sloType = SLO_OPTION_VALUES.both;
109
+ }
110
+ },
111
+
91
112
  async mixinFetch() {
92
113
  this.authConfigName = this.$route.params.id;
93
114
 
@@ -115,20 +136,16 @@ export default {
115
136
  if (this.model.openLdapConfig) {
116
137
  this.showLdap = true;
117
138
  }
118
- if (this.value.configType === 'saml') {
139
+
140
+ // Logic for Single Logout/SLO for auth providers
141
+ if (this.value?.configType && SLO_AUTH_PROVIDERS.includes(this.value?.configType)) {
119
142
  if (!this.model.rancherApiHost || !this.model.rancherApiHost.length) {
120
143
  this.model['rancherApiHost'] = this.serverUrl;
121
144
  }
122
145
 
123
146
  // setting data for SLO
124
147
  if (this.model && Object.keys(this.model).includes('logoutAllSupported')) {
125
- if (!this.model.logoutAllEnabled && !this.model.logoutAllForced) {
126
- this.sloType = SLO_OPTION_VALUES.rancher;
127
- } else if (this.model.logoutAllEnabled && this.model.logoutAllForced) {
128
- this.sloType = SLO_OPTION_VALUES.all;
129
- } else if (this.model.logoutAllEnabled && !this.model.logoutAllForced) {
130
- this.sloType = SLO_OPTION_VALUES.both;
131
- }
148
+ this.setSloType(this.model);
132
149
  }
133
150
  }
134
151
 
@@ -220,7 +237,7 @@ export default {
220
237
  addObject(this.model.allowedPrincipalIds, this.principal.id);
221
238
  }
222
239
  // Session has switched to new 'me', ensure we react
223
- this.$store.commit('auth/loggedInAs', this.principal.id);
240
+ this.$store.dispatch('auth/loggedInAs', this.principal.id);
224
241
  } else {
225
242
  console.warn(`Unable to find principal marked as 'me'`); // eslint-disable-line no-console
226
243
  }
@@ -292,6 +309,12 @@ export default {
292
309
  // must be cancelling edit of an enabled config; reset any changes and return to add users/groups view for that config
293
310
  this.$store.dispatch(`rancher/clone`, { resource: this.originalModel }).then((cloned) => {
294
311
  this.model = cloned;
312
+
313
+ // reset SLO type (radio option)
314
+ if (cloned && Object.keys(cloned).includes('logoutAllSupported')) {
315
+ this.setSloType(cloned);
316
+ }
317
+
295
318
  this.editConfig = false;
296
319
  });
297
320
  }
package/mixins/chart.js CHANGED
@@ -247,7 +247,7 @@ export default {
247
247
  }
248
248
 
249
249
  return {
250
- name: 'downgrade', tKey: 'downgrade', icon: 'icon-history'
250
+ name: 'downgrade', tKey: 'downgrade', icon: 'icon-downgrade-alt'
251
251
  };
252
252
  },
253
253
 
@@ -278,7 +278,7 @@ export default class MgmtCluster extends SteveModel {
278
278
 
279
279
  // Color to use as the underline for the icon in the app bar
280
280
  get iconColor() {
281
- return this.metadata?.annotations[CLUSTER_BADGE.COLOR];
281
+ return this.metadata?.annotations?.[CLUSTER_BADGE.COLOR];
282
282
  }
283
283
 
284
284
  // Custom badge to show for the Cluster (if the appropriate annotations are set)
@@ -43,7 +43,7 @@ export default class Workload extends WorkloadService {
43
43
  insertAt(out, 0, {
44
44
  action: 'toggleRollbackModal',
45
45
  label: this.t('action.rollback'),
46
- icon: 'icon icon-history',
46
+ icon: 'icon icon-downgrade-alt',
47
47
  enabled: !!this.links.update,
48
48
  });
49
49
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rancher/shell",
3
- "version": "3.0.5-rc.9",
3
+ "version": "3.0.5",
4
4
  "description": "Rancher Dashboard Shell",
5
5
  "repository": "https://github.com/rancherlabs/dashboard",
6
6
  "license": "Apache-2.0",
@@ -134,7 +134,8 @@ export default {
134
134
  },
135
135
 
136
136
  async fetch() {
137
- const username = this.$cookies.get(USERNAME, { parseJSON: false }) || '';
137
+ const cookie = this.$store.getters['cookies/get']({ key: USERNAME, options: { parseJSON: false } });
138
+ const username = cookie || '';
138
139
 
139
140
  this.username = username;
140
141
  this.remember = !!username;
@@ -272,15 +273,19 @@ export default {
272
273
  }
273
274
 
274
275
  if ( this.remember ) {
275
- this.$cookies.set(USERNAME, this.username, {
276
+ const options = {
276
277
  encode: (x) => x,
277
278
  maxAge: 86400 * 365,
278
279
  path: '/',
279
280
  sameSite: true,
280
281
  secure: true,
282
+ };
283
+
284
+ this.$store.commit('cookies/set', {
285
+ key: USERNAME, value: this.username, options
281
286
  });
282
287
  } else {
283
- this.$cookies.remove(USERNAME);
288
+ this.$store.commit('cookies/remove', { key: USERNAME });
284
289
  }
285
290
 
286
291
  // User logged with local login - we don't do any redirect/reload, so the boot-time plugin will not run again to laod the plugins
@@ -1,19 +1,20 @@
1
1
  <script>
2
2
  import { configType } from '@shell/models/management.cattle.io.authconfig';
3
+ import { SLO_AUTH_PROVIDERS } from '@shell/store/auth';
3
4
 
4
5
  export default {
5
6
  async fetch() {
6
7
  const publicAuthProviders = await this.$store.dispatch('auth/getAuthProviders');
7
8
 
8
- const samlAuthProvider = publicAuthProviders.find((authProvider) => configType[authProvider.id] === 'saml');
9
+ const sloAuthProvider = publicAuthProviders.find((authProvider) => SLO_AUTH_PROVIDERS.includes(configType[authProvider?.id]));
9
10
 
10
- if (!!samlAuthProvider) {
11
- const { logoutAllSupported, logoutAllEnabled, logoutAllForced } = samlAuthProvider;
11
+ if (!!sloAuthProvider) {
12
+ const { logoutAllSupported, logoutAllEnabled, logoutAllForced } = sloAuthProvider;
12
13
 
13
14
  if (logoutAllSupported && logoutAllEnabled && logoutAllForced) {
14
- // SAML - force SLO (logout from all apps)
15
+ // force SLO (logout from all apps)
15
16
  await this.$store.dispatch('auth/logout', {
16
- force: true, slo: true, provider: samlAuthProvider
17
+ force: true, slo: true, provider: sloAuthProvider
17
18
  }, { root: true });
18
19
  } else {
19
20
  // simple logout
@@ -117,7 +117,7 @@ describe('page: cluster tools', () => {
117
117
  });
118
118
  expect(actions[2]).toStrictEqual({
119
119
  label: 'catalog.tools.action.downgrade',
120
- icon: 'icon-history',
120
+ icon: 'icon-downgrade-alt',
121
121
  action: 'downgrade'
122
122
  });
123
123
  expect(actions[3]).toStrictEqual({ divider: true });
@@ -158,7 +158,7 @@ export default {
158
158
  if (currentIndex !== -1 && currentIndex < versions.length - 1) {
159
159
  actions.push({
160
160
  label: this.t('catalog.tools.action.downgrade'),
161
- icon: 'icon-history',
161
+ icon: 'icon-downgrade-alt',
162
162
  action: 'downgrade',
163
163
  });
164
164
  }
package/plugins/axios.js CHANGED
@@ -2,13 +2,14 @@ import https from 'https';
2
2
  import { CSRF } from '@shell/config/cookies';
3
3
 
4
4
  export default function({
5
- $axios, $cookies, isDev, req
5
+ $axios, store, isDev, req
6
6
  }) {
7
7
  $axios.defaults.headers.common['Accept'] = 'application/json';
8
8
  $axios.defaults.withCredentials = true;
9
9
 
10
10
  $axios.onRequest((config) => {
11
- const csrf = $cookies.get(CSRF, { parseJSON: false });
11
+ const options = { parseJSON: false };
12
+ const csrf = store.getters['cookies/get']({ key: CSRF, options });
12
13
 
13
14
  if ( csrf ) {
14
15
  config.headers['x-api-csrf'] = csrf;
@@ -1,13 +1,17 @@
1
1
  import { REDIRECTED } from '@shell/config/cookies';
2
2
 
3
- export default function({ $cookies }) {
3
+ export default function({ store }) {
4
4
  // This tells Ember not to redirect back to us once you've already been to dashboard once.
5
5
  // TODO: Remove this once the ember portion of the app is no longer needed
6
- if ( !$cookies.get(REDIRECTED) ) {
7
- $cookies.set(REDIRECTED, 'true', {
6
+ if ( !store.getters['cookies/get']({ key: REDIRECTED })) {
7
+ const options = {
8
8
  path: '/',
9
9
  sameSite: true,
10
10
  secure: true,
11
+ };
12
+
13
+ store.commit('cookies/set', {
14
+ key: REDIRECTED, value: 'true', options
11
15
  });
12
16
  }
13
17
  }
@@ -369,13 +369,15 @@ const sharedActions = {
369
369
  if (!this.$workers[getters.storeName]) {
370
370
  await createWorker(this, ctx);
371
371
  }
372
+ const options = { parseJSON: false };
373
+ const csrf = rootGetters['cookies/get']({ key: CSRF, options });
372
374
 
373
375
  // if the worker is in advanced mode then it'll contain it's own socket which it calls a 'watcher'
374
376
  this.$workers[getters.storeName].postMessage({
375
377
  createWatcher: {
376
378
  metadata,
377
- url: `${ state.config.baseUrl }/subscribe`,
378
- csrf: this.$cookies.get(CSRF, { parseJSON: false }),
379
+ url: `${ state.config.baseUrl }/subscribe`,
380
+ csrf,
379
381
  maxTries
380
382
  }
381
383
  });
@@ -239,7 +239,6 @@ function clone_repo_test_extension_build() {
239
239
  clone_repo_test_extension_build "rancher" "kubewarden-ui" "kubewarden"
240
240
  clone_repo_test_extension_build "rancher" "elemental-ui" "elemental"
241
241
  clone_repo_test_extension_build "neuvector" "manager-ext" "neuvector-ui-ext"
242
- clone_repo_test_extension_build "rancher" "capi-ui-extension" "capi"
243
242
  clone_repo_test_extension_build "StackVista" "rancher-extension-stackstate" "observability"
244
243
  clone_repo_test_extension_build "harvester" "harvester-ui-extension" "harvester"
245
244
 
@@ -0,0 +1,72 @@
1
+ import cookieStore from '../cookies';
2
+
3
+ // Mock cookie-universal
4
+ const mockCookie = {
5
+ get: jest.fn(),
6
+ set: jest.fn(),
7
+ remove: jest.fn(),
8
+ getAll: jest.fn(),
9
+ addChangeListener: jest.fn(),
10
+ removeChangeListener: jest.fn()
11
+ };
12
+
13
+ jest.mock('cookie-universal', () => {
14
+ return jest.fn(() => mockCookie);
15
+ });
16
+
17
+ describe('store: cookies', () => {
18
+ let state: any;
19
+
20
+ beforeEach(() => {
21
+ state = cookieStore.state();
22
+ // Reset mocks before each test
23
+ mockCookie.get.mockClear();
24
+ mockCookie.set.mockClear();
25
+ mockCookie.remove.mockClear();
26
+ });
27
+
28
+ describe('getters', () => {
29
+ it('get should call cookies.get with the correct parameters', () => {
30
+ const { getters } = cookieStore;
31
+ const key = 'test-key';
32
+ const options = { from: 'server' };
33
+
34
+ getters.get(state, {}, {}, {})({ key, options });
35
+ expect(mockCookie.get).toHaveBeenCalledWith(key, options);
36
+ });
37
+ });
38
+
39
+ describe('mutations', () => {
40
+ it('set should call cookies.set with the correct parameters', () => {
41
+ const { mutations } = cookieStore;
42
+ const key = 'test-key';
43
+ const value = { data: 'test-value' };
44
+ const options = { path: '/' };
45
+
46
+ mutations.set(state, {
47
+ key, value, options
48
+ });
49
+ expect(mockCookie.set).toHaveBeenCalledWith(key, value, options);
50
+ });
51
+
52
+ it('remove should call cookies.remove with the correct key', () => {
53
+ const { mutations } = cookieStore;
54
+ const key = 'test-key';
55
+
56
+ mutations.remove(state, { key });
57
+ expect(mockCookie.remove).toHaveBeenCalledWith(key);
58
+ });
59
+ });
60
+
61
+ describe('state', () => {
62
+ it('should return a cookies object', () => {
63
+ expect(state.cookies).toBeDefined();
64
+ });
65
+ });
66
+
67
+ describe('namespaced', () => {
68
+ it('should be namespaced', () => {
69
+ expect(cookieStore.namespaced).toBe(true);
70
+ });
71
+ });
72
+ });
package/store/auth.js CHANGED
@@ -8,6 +8,13 @@ import { removeEmberPage } from '@shell/utils/ember-page';
8
8
  import { randomStr } from '@shell/utils/string';
9
9
  import { addParams, parse as parseUrl, removeParam } from '@shell/utils/url';
10
10
 
11
+ // configuration for Single Logout/SLO
12
+ // admissable auth providers compatible with SLO, based on shell/models/management.cattle.io.authconfig "configType"
13
+ export const SLO_AUTH_PROVIDERS = ['oidc', 'saml'];
14
+
15
+ // this is connected to the redirect url, for which the logic can be found in "shell/store/auth"
16
+ const SLO_TOKENS_ENDPOINT_LOGOUT_RES_BASETYPE = ['authConfigLogoutOutput'];
17
+
11
18
  export const BASE_SCOPES = {
12
19
  github: ['read:org'],
13
20
  googleoauth: ['openid profile email'],
@@ -85,8 +92,6 @@ export const mutations = {
85
92
  loggedInAs(state, principalId) {
86
93
  state.loggedIn = true;
87
94
  state.principalId = principalId;
88
-
89
- this.$cookies.remove(KEY);
90
95
  },
91
96
 
92
97
  loggedOut(state) {
@@ -136,10 +141,18 @@ export const actions = {
136
141
  commit('initialPass', pass);
137
142
  },
138
143
 
139
- getAuthProviders({ dispatch }) {
144
+ getAuthProviders({ dispatch }, opt) {
145
+ let force = false;
146
+
147
+ if (opt?.force) {
148
+ force = true;
149
+ }
150
+
140
151
  return dispatch('rancher/findAll', {
141
152
  type: 'authProvider',
142
- opt: { url: `/v3-public/authProviders`, watch: false }
153
+ opt: {
154
+ url: `/v3-public/authProviders`, watch: false, force
155
+ }
143
156
  }, { root: true });
144
157
  },
145
158
 
@@ -183,13 +196,17 @@ export const actions = {
183
196
  * Save nonce details. Information it contains will be used to validate auth requests/responses
184
197
  * Note - this may be structurally different than the nonce we encode and send
185
198
  */
186
- saveNonce(ctx, opt) {
199
+ saveNonce({ commit }, opt) {
187
200
  const strung = JSON.stringify(opt);
188
201
 
189
- this.$cookies.set(KEY, strung, {
202
+ const options = {
190
203
  path: '/',
191
204
  sameSite: true,
192
205
  secure: true,
206
+ };
207
+
208
+ commit('cookies/set', {
209
+ key: KEY, value: strung, options
193
210
  });
194
211
 
195
212
  return strung;
@@ -265,8 +282,8 @@ export const actions = {
265
282
  }
266
283
  },
267
284
 
268
- verifyOAuth({ dispatch }, { nonce, code, provider }) {
269
- const expectJSON = this.$cookies.get(KEY, { parseJSON: false });
285
+ verifyOAuth({ dispatch, rootGetters }, { nonce, code, provider }) {
286
+ const expectJSON = rootGetters['cookies/get']({ key: KEY, options: { parseJSON: false } });
270
287
  let parsed;
271
288
 
272
289
  try {
@@ -351,6 +368,12 @@ export const actions = {
351
368
  }
352
369
  },
353
370
 
371
+ loggedInAs({ commit }, principalId) {
372
+ commit('loggedInAs', principalId);
373
+
374
+ commit('cookies/remove', { key: KEY });
375
+ },
376
+
354
377
  uiLogout({ commit, dispatch }) {
355
378
  removeEmberPage();
356
379
 
@@ -398,8 +421,8 @@ export const actions = {
398
421
  redirectUnauthorized: false,
399
422
  }, { root: true });
400
423
 
401
- // Single-sign logout for SAML providers that allow for it
402
- if (res.baseType === 'samlConfigLogoutOutput' && res.idpRedirectUrl) {
424
+ // Single-sign logout redirect for SLO compatible auth providers
425
+ if (SLO_TOKENS_ENDPOINT_LOGOUT_RES_BASETYPE.includes(res.baseType) && res.idpRedirectUrl) {
403
426
  window.location.href = res.idpRedirectUrl;
404
427
 
405
428
  return;
@@ -0,0 +1,30 @@
1
+ import { MutationTree, GetterTree, ActionTree } from 'vuex';
2
+ import Cookie, { ICookie, ICookieGetOpts } from 'cookie-universal';
3
+
4
+ type State = { cookies: ICookie };
5
+ const options = { parseJSON: true };
6
+ const state = (): State => ({ cookies: Cookie(undefined, undefined, options.parseJSON) });
7
+
8
+ const getters: GetterTree<State, any> = {
9
+ get(state) {
10
+ return ({ key, options }: {key: string, options?: ICookieGetOpts}) => state.cookies.get(key, options);
11
+ }
12
+ };
13
+ const mutations: MutationTree<State> = {
14
+ set(state, { key, value, options }) {
15
+ return state.cookies.set(key, value, options);
16
+ },
17
+
18
+ remove(state, { key }) {
19
+ return state.cookies.remove(key);
20
+ },
21
+ };
22
+ const actions: ActionTree<State, any> = {};
23
+
24
+ export default {
25
+ namespaced: true,
26
+ state,
27
+ getters,
28
+ mutations,
29
+ actions
30
+ };
package/store/prefs.js CHANGED
@@ -289,12 +289,16 @@ export const actions = {
289
289
  commit('load', { key, value });
290
290
 
291
291
  if ( definition.asCookie ) {
292
- const opt = {
292
+ const options = {
293
293
  ...cookieOptions,
294
294
  parseJSON: definition.parseJSON === true
295
295
  };
296
296
 
297
- this.$cookies.set(`${ cookiePrefix }${ key }`.toUpperCase(), value, opt);
297
+ const computedKey = `${ cookiePrefix }${ key }`.toUpperCase();
298
+
299
+ commit('cookies/set', {
300
+ key: computedKey, value, options
301
+ }, { root: true });
298
302
  }
299
303
 
300
304
  if ( definition.asUserPreference ) {
@@ -336,7 +340,7 @@ export const actions = {
336
340
  await dispatch('set', { key: THEME, value: val });
337
341
  },
338
342
 
339
- loadCookies({ state, commit }) {
343
+ loadCookies({ state, commit, rootGetters }) {
340
344
  if ( state.cookiesLoaded ) {
341
345
  return;
342
346
  }
@@ -348,8 +352,9 @@ export const actions = {
348
352
  continue;
349
353
  }
350
354
 
351
- const opt = { parseJSON: definition.parseJSON === true };
352
- const value = this.$cookies.get(`${ cookiePrefix }${ key }`.toUpperCase(), opt);
355
+ const options = { parseJSON: definition.parseJSON === true };
356
+ const computedKey = `${ cookiePrefix }${ key }`.toUpperCase();
357
+ const value = rootGetters['cookies/get']({ key: computedKey, options });
353
358
 
354
359
  if (value !== undefined) {
355
360
  commit('load', { key, value });
@@ -3601,9 +3601,10 @@ export namespace actions {
3601
3601
  function setTheme({ dispatch }: {
3602
3602
  dispatch: any;
3603
3603
  }, val: any): Promise<void>;
3604
- function loadCookies({ state, commit }: {
3604
+ function loadCookies({ state, commit, rootGetters }: {
3605
3605
  state: any;
3606
3606
  commit: any;
3607
+ rootGetters: any;
3607
3608
  }): void;
3608
3609
  function loadTheme({ dispatch }: {
3609
3610
  dispatch: any;
@@ -3850,16 +3851,6 @@ declare function _default(context: any, inject: any): void;
3850
3851
  export default _default;
3851
3852
  }
3852
3853
 
3853
- // @shell/utils/cookie-universal
3854
-
3855
- declare module '@shell/utils/cookie-universal' {
3856
- declare function _default({ req, res }: {
3857
- req: any;
3858
- res: any;
3859
- }, inject: any): void;
3860
- export default _default;
3861
- }
3862
-
3863
3854
  // @shell/utils/create-yaml
3864
3855
 
3865
3856
  declare module '@shell/utils/create-yaml' {
package/utils/auth.js CHANGED
@@ -263,7 +263,7 @@ export async function tryInitialSetup(store, password = 'admin') {
263
263
  */
264
264
  export async function isLoggedIn(store, userData) {
265
265
  store.commit('auth/hasAuth', true);
266
- store.commit('auth/loggedInAs', userData.id);
266
+ store.dispatch('auth/loggedInAs', userData.id);
267
267
 
268
268
  // Init the notification center now that we know who the user is
269
269
  await store.dispatch('notifications/init', userData);
@@ -1,10 +0,0 @@
1
- import cookieUniversal from 'cookie-universal';
2
-
3
- export default ({ req, res }, inject) => {
4
- const options = {
5
- alias: 'cookies',
6
- parseJSON: true
7
- };
8
-
9
- inject(options.alias, cookieUniversal(req, res, options.parseJSON));
10
- };