diff --git a/web/composables/services/keyServer.ts b/web/composables/services/keyServer.ts
index 36da17892..ea627d8f0 100644
--- a/web/composables/services/keyServer.ts
+++ b/web/composables/services/keyServer.ts
@@ -1,5 +1,7 @@
import { request } from '~/composables/services/request';
+import type { Release } from '~/store/updateOs';
+
const KeyServer = request.url('https://keys.lime-technology.com');
export interface StartTrialPayload {
@@ -10,7 +12,7 @@ export interface StartTrialResponse {
license?: string;
trial?: string
}
-export const startTrial = (payload: StartTrialPayload) => KeyServer
+export const startTrial = async (payload: StartTrialPayload) => await KeyServer
.url('/account/trial')
.formUrl(payload)
.post();
@@ -28,10 +30,11 @@ export interface ValidateGuidPayload {
guid: string;
keyfile?: string;
}
-export const validateGuid = (payload: ValidateGuidPayload) => KeyServer
+export const validateGuid = async (payload: ValidateGuidPayload) => await KeyServer
.url('/validate/guid')
.formUrl(payload)
- .post();
+ .post()
+ .json();
export interface KeyLatestPayload {
keyfile: string;
@@ -39,7 +42,12 @@ export interface KeyLatestPayload {
export interface KeyLatestResponse {
license: string;
}
-export const keyLatest = (payload: KeyLatestPayload) => KeyServer
+export const keyLatest = async (payload: KeyLatestPayload) => await KeyServer
.url('/key/latest')
.formUrl(payload)
- .post();
\ No newline at end of file
+ .post();
+
+export const getOsReleaseBySha256 = async (sha256: string): Release => await KeyServer
+ .url(`/versions/sha256/${sha256}`)
+ .get()
+ .json();
\ No newline at end of file
diff --git a/web/store/callbackActions.ts b/web/store/callbackActions.ts
index e3217e52b..a1d57c6a4 100644
--- a/web/store/callbackActions.ts
+++ b/web/store/callbackActions.ts
@@ -34,7 +34,8 @@ export const useCallbackActionsStore = defineStore('callbackActions', () => {
redirectToCallbackType?.();
};
- const redirectToCallbackType = () => {
+ const redirectToCallbackType = async () => {
+ console.debug('[redirectToCallbackType]');
if (!callbackData.value || !callbackData.value.type || callbackData.value.type !== 'forUpc' || !callbackData.value.actions?.length) {
callbackError.value = 'Callback redirect type not present or incorrect';
callbackStatus.value = 'ready'; // default status
@@ -45,6 +46,8 @@ export const useCallbackActionsStore = defineStore('callbackActions', () => {
// Parse the data and perform actions
callbackData.value.actions.forEach(async (action, index, array) => {
+ console.debug('[redirectToCallbackType]', { action, index, array });
+
if (action?.keyUrl) {
await installKeyStore.install(action as ExternalKeyActions);
}
@@ -61,13 +64,16 @@ export const useCallbackActionsStore = defineStore('callbackActions', () => {
accountStore.setQueueConnectSignOut(true);
}
- if (action.type === 'updateOs' && action?.releaseHash) {
- const foundRelease = updateOsStore.findReleaseByMd5(action.releaseHash);
+ if (action.type === 'updateOs' && action?.sha256) {
+ console.debug('[redirectToCallbackType] updateOs', action);
+ const foundRelease = await updateOsActionsStore.getReleaseFromKeyServer(action.sha256);
+ console.debug('[redirectToCallbackType] updateOs foundRelease', foundRelease);
if (!foundRelease) {
throw new Error('Release not found');
}
updateOsActionsStore.confirmUpdateOs(foundRelease);
if (array.length === 1) { // only 1 action, skip refresh server state
+ console.debug('[redirectToCallbackType] updateOs done');
// removing query string relase is set so users can't refresh the page and go through the same actions
window.history.replaceState(null, '', window.location.pathname);
return
diff --git a/web/store/replaceRenew.ts b/web/store/replaceRenew.ts
index 1095ed638..0695332f0 100644
--- a/web/store/replaceRenew.ts
+++ b/web/store/replaceRenew.ts
@@ -13,6 +13,7 @@ import {
type ValidateGuidResponse,
} from '~/composables/services/keyServer';
import { WebguiNotify } from '~/composables/services/webgui';
+import { useCallbackStore } from '~/store/callbackActions';
import { useInstallKeyStore } from '~/store/installKey';
import { useServerStore } from '~/store/server';
import type { UiBadgeProps } from '~/types/ui/badge';
@@ -36,6 +37,7 @@ interface CachedValidationResponse extends ValidateGuidResponse {
export const REPLACE_CHECK_LOCAL_STORAGE_KEY = 'unraidReplaceCheck';
export const useReplaceRenewStore = defineStore('replaceRenewCheck', () => {
+ const callbackStore = useCallbackStore();
const installKeyStore = useInstallKeyStore();
const serverStore = useServerStore();
@@ -124,7 +126,7 @@ export const useReplaceRenewStore = defineStore('replaceRenewCheck', () => {
response = await validateGuid({
guid: guid.value,
keyfile: keyfile.value,
- }).json();
+ });
}
setReplaceStatus(response?.replaceable ? 'eligible' : 'ineligible');
@@ -146,25 +148,34 @@ export const useReplaceRenewStore = defineStore('replaceRenewCheck', () => {
}).json();
if (keyLatestResponse?.license) {
- setRenewStatus('installing');
+ callbackStore.send(
+ window.location.origin,
+ [{
+ keyUrl: keyLatestResponse.license,
+ type: 'renew',
+ }],
+ false,
+ 'forUpc',
+ );
+ // setRenewStatus('installing');
- await installKeyStore.install({
- keyUrl: keyLatestResponse.license,
- type: 'renew',
- }).then(() => {
- setRenewStatus('installed');
- // reset the validation response so we can check again on the subsequent page load. Will also prevent the keyfile from being installed again on page refresh.
- purgeValidationResponse();
- /** @todo this doesn't work */
- WebguiNotify({
- cmd: 'add',
- csrf_token: serverStore.csrf,
- e: 'Keyfile Renewed and Installed (event)',
- s: 'Keyfile Renewed and Installed (subject)',
- d: 'While license keys are perpetual, certain keyfiles are not. Your keyfile has automatically been renewed and installed in the background. Thanks for your support!',
- m: 'Your keyfile has automatically been renewed and installed in the background. Thanks for your support!',
- })
- });
+ // await installKeyStore.install({
+ // keyUrl: keyLatestResponse.license,
+ // type: 'renew',
+ // }).then(() => {
+ // setRenewStatus('installed');
+ // // reset the validation response so we can check again on the subsequent page load. Will also prevent the keyfile from being installed again on page refresh.
+ // purgeValidationResponse();
+ // /** @todo this doesn't work */
+ // WebguiNotify({
+ // cmd: 'add',
+ // csrf_token: serverStore.csrf,
+ // e: 'Keyfile Renewed and Installed (event)',
+ // s: 'Keyfile Renewed and Installed (subject)',
+ // d: 'While license keys are perpetual, certain keyfiles are not. Your keyfile has automatically been renewed and installed in the background. Thanks for your support!',
+ // m: 'Your keyfile has automatically been renewed and installed in the background. Thanks for your support!',
+ // })
+ // });
}
}
} catch (err) {
diff --git a/web/store/updateOs.ts b/web/store/updateOs.ts
index aa520063f..843a41c1d 100644
--- a/web/store/updateOs.ts
+++ b/web/store/updateOs.ts
@@ -25,17 +25,20 @@ export interface RequestReleasesPayload {
}
export interface Release {
- version: string; // 6.12.4
- name: string; // Unraid Server 6.12.4
- basefile: string; // unRAIDServer-6.12.4-x86_64.zip
- date: string; // 2023-08-31
- url: string; // https://dl.stable.unraid.net/unRAIDServer-6.12.4-x86_64.zip
- changelog: string; // https://unraid.net/blog/unraid-os-6.12.4-release-notes
- md5: string; // 9050bddcf415f2d0518804e551c1be98
- size: number; // 12345122
- sha256: string; // fda177bb1336270b24e4df0fd0c1dd0596c44699204f57c83ce70a0f19173be4
- plugin_url: string; // https://dl.stable.unraid.net/unRAIDServer-6.12.4.plg
- plugin_sha256: string; // 83850536ed6982bd582ed107d977d59e9b9b786363e698b14d1daf52e2dec2d9"
+ version: string; // "6.12.4"
+ name: string; // "Unraid 6.12.4"
+ basefile: string; // "unRAIDServer-6.12.4-x86_64.zip"
+ date: string; // "2023-08-31"
+ url: string; // "https://stable.dl.unraid.net/unRAIDServer-6.12.4-x86_64.zip"
+ changelog: string; // "https://raw.githubusercontent.com/unraid/docs/main/docs/unraid-os/release-notes/6.12.4.md"
+ changelog_pretty: string; // "https://docs.unraid.net/unraid-os/release-notes/6.12.4/"
+ md5: string; // "df6e5859d28c14617efde36d59458206"
+ size: string; // "439999418"
+ sha256: string; // "5ad2d22e8c124e3b925c3bd05f1d782d8521965aabcbedd7dd782db76afd9ace"
+ plugin_url: string; // "https://stable.dl.unraid.net/unRAIDServer-6.12.4.plg"
+ plugin_sha256: string; // "57d2ab6036e663208b3f72298ceb478b937b17e333986e68dcae2696c88ed152"
+ announce_url: string; // "https://unraid.net/blog/6-12-4"
+ branch: 'stable' | 'next' | 'preview' | 'test'; // "stable"
}
export interface ReleasesResponse {
stable: Release[];
@@ -294,46 +297,19 @@ export const useUpdateOsStoreGeneric = (
});
};
- const findReleaseByMd5 = (releaseMd5: string): Release | null => {
- let releaseForReturn: Release | null = null;
-
- Object.keys(releases.value?.response ?? {}).forEach(key => {
- const branchReleases = releases.value?.response[key as keyof ReleasesResponse];
-
- if (releaseForReturn || !branchReleases || branchReleases.length == 0) {
- return;
- }
-
- branchReleases.find(release => {
- if (release.md5 === releaseMd5) {
- releaseForReturn = release;
- return releaseForReturn;
- }
- });
- });
-
- return releaseForReturn;
- };
-
const findRelease = (searchKey: keyof Release, searchValue: string): Release | null => {
- let releaseForReturn: Release | null = null;
+ const response = releases?.value?.response;
+ if (!response) return null;
- Object.keys(releases.value?.response ?? {}).forEach(key => {
- const branchReleases = releases.value?.response[key as keyof ReleasesResponse];
+ for (const key of Object.keys(response)) {
+ const branchReleases = response[key as keyof ReleasesResponse];
+ if (!branchReleases || branchReleases.length === 0) continue;
- if (releaseForReturn || !branchReleases || branchReleases.length == 0) {
- return;
- }
+ const foundRelease = branchReleases.find(release => release[searchKey] === searchValue);
+ if (foundRelease) return foundRelease;
+ }
- branchReleases.find(release => {
- if (release[searchKey] === searchValue) {
- releaseForReturn = release;
- return release;
- }
- });
- });
-
- return releaseForReturn;
+ return null;
};
const isVersionStable = (version: SemVer | string): boolean => prerelease(version) === null;
@@ -363,7 +339,6 @@ export const useUpdateOsStoreGeneric = (
allFilteredReleases,
// actions
checkForUpdate,
- findReleaseByMd5,
findRelease,
requestReleases,
isVersionStable,
diff --git a/web/store/updateOsActions.ts b/web/store/updateOsActions.ts
index dd6dcc0b3..51d0e4cea 100644
--- a/web/store/updateOsActions.ts
+++ b/web/store/updateOsActions.ts
@@ -2,6 +2,7 @@ import { BellAlertIcon } from '@heroicons/vue/24/solid';
import { defineStore, createPinia, setActivePinia } from 'pinia';
import useInstallPlugin from '~/composables/installPlugin';
+import { getOsReleaseBySha256 } from '~/composables/services/keyServer';
import { ACCOUNT_CALLBACK, WEBGUI_TOOLS_UPDATE } from '~/helpers/urls';
@@ -114,8 +115,20 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => {
};
/**
- * @description When receiving the callback the Account update page we'll use the provided releaseMd5 to find the release in the releases cache.
+ * @description When receiving the callback the Account update page we'll use the provided sha256 of the release to get the release from the keyserver
*/
+ const getReleaseFromKeyServer = async (sha256: string): Release => {
+ console.debug('[getReleaseFromKeyServer]', sha256)
+ try {
+ const response = await getOsReleaseBySha256(sha256);
+ console.debug('[getReleaseFromKeyServer]', response);
+ return response;
+ } catch (error) {
+ console.error(error);
+ throw new Error('Unable to get release from keyserver');
+ }
+ };
+
const confirmUpdateOs = async (release: Release) => {
callbackUpdateRelease.value = release;
setStatus('confirming');
@@ -130,7 +143,7 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => {
installPlugin({
modalTitle: `${callbackUpdateRelease.value.name} Update`,
pluginUrl: callbackUpdateRelease.value.plugin_url,
- update: true,
+ update: false,
});
};
@@ -186,6 +199,7 @@ export const useUpdateOsActionsStore = defineStore('updateOsActions', () => {
setStatus,
setRebootType,
viewCurrentReleaseNotes,
+ getReleaseFromKeyServer,
};
});