mirror of
https://github.com/decaf-dev/obsidian-vault-explorer.git
synced 2026-07-22 10:10:31 +00:00
Update license system (#275)
* feat: simplify key logic * docs: update network section of README * refactor: rename to "Premium features are enabled" * docs: fix grammar * feat: clean up old values * feat: implement digital signature validation * refactor: add clean up message
This commit is contained in:
parent
aa89170746
commit
c3b06261e1
15 changed files with 192 additions and 353 deletions
|
|
@ -87,6 +87,8 @@ Click the compass button on the left-hand sidebar to open the vault explorer vie
|
|||
|
||||
Premium features are available to users who purchase a [Vault Explorer license](https://vaultexplorer.com/docs/premium/).
|
||||
|
||||
Please do not share your license key with anyone. Shared license keys will be deactivated.
|
||||
|
||||
## Features
|
||||
|
||||
| Name | Categories | Documented |
|
||||
|
|
@ -159,11 +161,11 @@ Premium features are available to users who purchase a [Vault Explorer license](
|
|||
|
||||
## Network use
|
||||
|
||||
For general usage of the plugin, Vault Explorer does not make any network requests.
|
||||
Vault Explorer is a privacy friendly plugin.
|
||||
|
||||
If you purchase a Vault Explorer license, the plugin will communicate with the Vault Explorer API. These requests will only send the license key you enter and a device ID generated by the plugin.
|
||||
When you access the grid view, Vault Explorer will make requests to the URL's that you specify to display cover images. You may disable this behavior in the settings.
|
||||
|
||||
When you access the grid view and have configured an image URL property in the settings, Vault Explorer will request the specified URLs to display cover images on corresponding grid cards.
|
||||
Besides cover image fetching, Vault Explorer does not make any network requests.
|
||||
|
||||
Vault Explorer does not include any client-side telemetry.
|
||||
|
||||
|
|
|
|||
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "vault-explorer",
|
||||
"name": "Vault Explorer",
|
||||
"version": "1.35.1",
|
||||
"version": "1.36.0",
|
||||
"minAppVersion": "1.4.13",
|
||||
"description": "Explore your vault in visual format",
|
||||
"author": "DecafDev",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-vault-explorer",
|
||||
"version": "1.35.1",
|
||||
"version": "1.36.0",
|
||||
"description": "Explore your vault in visual format",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
"typescript": "4.7.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"crypto": "^1.0.1",
|
||||
"idb": "^8.0.0",
|
||||
"js-logger": "^1.6.1",
|
||||
"lodash": "^4.17.21",
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ export enum PluginEvent {
|
|||
FEED_CONTENT_SETTING_CHANGE = "feed-content-setting-change",
|
||||
COVER_IMAGE_SOURCE_SETTING_CHANGE = "cover-image-source-setting-change",
|
||||
PROPERTY_SETTING_CHANGE = "property-setting-change",
|
||||
DEVICE_REGISTRATION_CHANGE = "device-registration-change",
|
||||
LICENSE_KEY_VALIDATION_CHANGE = "license-key-validation-change",
|
||||
CLOCK_UPDATES_SETTING_CHANGE = "clock-updates-setting-change",
|
||||
FILTER_TOGGLE_SETTING_CHANGE = "filter-toggle-setting-change",
|
||||
SCROLL_BUTTONS_SETTING_CHANGE = "scroll-buttons-setting-change",
|
||||
|
|
|
|||
24
src/main.ts
24
src/main.ts
|
|
@ -15,9 +15,9 @@ import { preformMigrations } from "./migrations";
|
|||
import Logger from "js-logger";
|
||||
import { formatMessageForLogger, stringToLogLevel } from "./logger";
|
||||
import { moveFocus } from "./focus-utils";
|
||||
import { loadDeviceId } from "./svelte/shared/services/device-id-utils";
|
||||
import License from "./svelte/shared/services/license";
|
||||
import { PluginEvent } from "./event/types";
|
||||
import { isVersionLessThan } from "./utils";
|
||||
import License from "./svelte/shared/services/license";
|
||||
|
||||
export default class VaultExplorerPlugin extends Plugin {
|
||||
settings: VaultExplorerPluginSettings = DEFAULT_SETTINGS;
|
||||
|
|
@ -27,6 +27,8 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
await this.loadSettings();
|
||||
this.setupLogger();
|
||||
|
||||
await License.getInstance().loadStoredKey();
|
||||
|
||||
this.registerView(
|
||||
VAULT_EXPLORER_VIEW,
|
||||
(leaf) => new VaultExplorerView(leaf, this)
|
||||
|
|
@ -54,9 +56,6 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
this.app.workspace.onLayoutReady(() => {
|
||||
this.layoutReady = true;
|
||||
});
|
||||
|
||||
await loadDeviceId();
|
||||
await License.getInstance().verifyLicense();
|
||||
}
|
||||
|
||||
private registerEvents() {
|
||||
|
|
@ -174,6 +173,21 @@ export default class VaultExplorerPlugin extends Plugin {
|
|||
if (loadedVersion !== null) {
|
||||
const newData = preformMigrations(loadedVersion, loadedData);
|
||||
currentData = newData;
|
||||
if (isVersionLessThan(loadedVersion, "1.36.0")) {
|
||||
console.log("Cleaning up old data");
|
||||
const LOCAL_STORAGE_DEVICE_REGISTERED =
|
||||
"vault-explorer-device-registration";
|
||||
localStorage.removeItem(LOCAL_STORAGE_DEVICE_REGISTERED);
|
||||
|
||||
//Clean up the old device id from the versioning system
|
||||
const LOCAL_STORAGE_ID = "vault-explorer-id";
|
||||
localStorage.removeItem(LOCAL_STORAGE_ID);
|
||||
|
||||
//Clean up the old device id from the versioning system
|
||||
const LOCAL_STORAGE_LICENSE_KEY =
|
||||
"vault-explorer-license-key";
|
||||
localStorage.removeItem(LOCAL_STORAGE_LICENSE_KEY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
import License from "src/svelte/shared/services/license";
|
||||
import FeedCard from "./feed-card.svelte";
|
||||
|
||||
export let isDeviceRegistered = false;
|
||||
export let hasValidLicenseKey = false;
|
||||
export let data: FileRenderData[] = [];
|
||||
export let startIndex;
|
||||
export let pageLength;
|
||||
|
|
@ -13,9 +13,9 @@
|
|||
let filteredItems: FileRenderData[] = [];
|
||||
|
||||
License.getInstance()
|
||||
.getIsDeviceRegisteredStore()
|
||||
.subscribe((isRegistered) => {
|
||||
isDeviceRegistered = isRegistered;
|
||||
.getHasValidKeyStore()
|
||||
.subscribe((hasValidKey) => {
|
||||
hasValidLicenseKey = hasValidKey;
|
||||
});
|
||||
|
||||
$: {
|
||||
|
|
@ -31,13 +31,13 @@
|
|||
</script>
|
||||
|
||||
<div class="vault-explorer-feed-view">
|
||||
{#if !isDeviceRegistered}
|
||||
{#if !hasValidLicenseKey}
|
||||
<div>
|
||||
<PremiumMessage />
|
||||
<PremiumLink />
|
||||
</div>
|
||||
{/if}
|
||||
{#if isDeviceRegistered}
|
||||
{#if hasValidLicenseKey}
|
||||
{#each filteredItems as fileRenderData (fileRenderData.id)}
|
||||
<FeedCard
|
||||
displayName={fileRenderData.displayName}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,12 @@
|
|||
import PremiumMessage from "src/svelte/shared/components/premium-message.svelte";
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
let isDeviceRegistered = false;
|
||||
let hasValidLicenseKey = false;
|
||||
|
||||
License.getInstance()
|
||||
.getIsDeviceRegisteredStore()
|
||||
.subscribe((isRegistered) => {
|
||||
isDeviceRegistered = isRegistered;
|
||||
.getHasValidKeyStore()
|
||||
.subscribe((hasValidKey) => {
|
||||
hasValidLicenseKey = hasValidKey;
|
||||
});
|
||||
|
||||
function handleValueChange(e: Event) {
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
{#if condition !== ContentFilterCondition.IS_EMPTY && condition !== ContentFilterCondition.IS_NOT_EMPTY}
|
||||
<input
|
||||
type="text"
|
||||
disabled={!isDeviceRegistered}
|
||||
disabled={!hasValidLicenseKey}
|
||||
placeholder="value"
|
||||
{value}
|
||||
on:input={handleValueChange}
|
||||
|
|
@ -62,7 +62,7 @@
|
|||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="after-toggle">
|
||||
{#if type === FilterRuleType.CONTENT && !isDeviceRegistered}
|
||||
{#if type === FilterRuleType.CONTENT && !hasValidLicenseKey}
|
||||
<div>
|
||||
<PremiumMessage />
|
||||
<PremiumLink />
|
||||
|
|
|
|||
|
|
@ -33,14 +33,14 @@
|
|||
export let condition: FilterCondition;
|
||||
export let isEnabled: boolean;
|
||||
|
||||
let isDeviceRegistered = false;
|
||||
let hasValidLicenseKey = false;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
License.getInstance()
|
||||
.getIsDeviceRegisteredStore()
|
||||
.subscribe((isRegistered) => {
|
||||
isDeviceRegistered = isRegistered;
|
||||
.getHasValidKeyStore()
|
||||
.subscribe((hasValidKey) => {
|
||||
hasValidLicenseKey = hasValidKey;
|
||||
});
|
||||
|
||||
function handleActionsClick(e: CustomEvent) {
|
||||
|
|
@ -142,7 +142,7 @@
|
|||
</select>
|
||||
<slot name="before-condition"></slot>
|
||||
<select
|
||||
disabled={type === FilterRuleType.CONTENT && !isDeviceRegistered}
|
||||
disabled={type === FilterRuleType.CONTENT && !hasValidLicenseKey}
|
||||
value={condition}
|
||||
on:change={handleConditionChange}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import License, { LICENSE_KEY_LENGTH } from "../shared/services/license";
|
||||
import License from "../shared/services/license";
|
||||
import EventManager from "src/event/event-manager";
|
||||
import PremiumLink from "../shared/components/premium-link.svelte";
|
||||
import { PluginEvent } from "src/event/types";
|
||||
|
|
@ -10,69 +10,61 @@
|
|||
text: string;
|
||||
}
|
||||
|
||||
let isDeviceRegistered = false;
|
||||
let hasValidLicenseKey = false;
|
||||
let message: Message | null = null;
|
||||
|
||||
const LICENSE_KEY_SIZE = 148;
|
||||
|
||||
onMount(() => {
|
||||
const registered = License.getInstance().getIsDeviceRegistered();
|
||||
if (registered) {
|
||||
const hasValidKey = License.getInstance().getHasValidKey();
|
||||
if (hasValidKey) {
|
||||
message = {
|
||||
type: "success",
|
||||
text: "This device is registered with a license key.",
|
||||
text: "Premium features are enabled.",
|
||||
};
|
||||
}
|
||||
isDeviceRegistered = registered;
|
||||
hasValidLicenseKey = hasValidKey;
|
||||
});
|
||||
|
||||
async function handleInputChange(e: Event) {
|
||||
const value = (e.target as HTMLInputElement).value;
|
||||
|
||||
if (value.length === LICENSE_KEY_LENGTH) {
|
||||
if (value.length < LICENSE_KEY_SIZE) return;
|
||||
|
||||
message = {
|
||||
type: "info",
|
||||
text: "Validating key...",
|
||||
};
|
||||
|
||||
const result = await License.getInstance().addKey(value);
|
||||
|
||||
if (result) {
|
||||
hasValidLicenseKey = true;
|
||||
message = {
|
||||
type: "info",
|
||||
text: "Registering device...",
|
||||
type: "success",
|
||||
text: "Premium features are enabled.",
|
||||
};
|
||||
|
||||
const result = await License.getInstance().registerDevice(value);
|
||||
|
||||
const responseMessage = License.getInstance().getResponseMessage();
|
||||
if (result) {
|
||||
isDeviceRegistered = true;
|
||||
message = {
|
||||
type: "success",
|
||||
text: responseMessage,
|
||||
};
|
||||
EventManager.getInstance().emit(
|
||||
PluginEvent.DEVICE_REGISTRATION_CHANGE,
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
message = {
|
||||
type: "failure",
|
||||
text: responseMessage,
|
||||
};
|
||||
}
|
||||
EventManager.getInstance().emit(
|
||||
PluginEvent.LICENSE_KEY_VALIDATION_CHANGE,
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
message = null;
|
||||
hasValidLicenseKey = false;
|
||||
message = {
|
||||
type: "failure",
|
||||
text: "Invalid key.",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function handleButtonClick() {
|
||||
const result = await License.getInstance().unregisterDevice();
|
||||
if (result) {
|
||||
isDeviceRegistered = false;
|
||||
message = null;
|
||||
EventManager.getInstance().emit(
|
||||
PluginEvent.DEVICE_REGISTRATION_CHANGE,
|
||||
false,
|
||||
);
|
||||
} else {
|
||||
const responseMessage = License.getInstance().getResponseMessage();
|
||||
message = {
|
||||
type: "failure",
|
||||
text: responseMessage,
|
||||
};
|
||||
}
|
||||
function handleRemoveButtonClick() {
|
||||
License.getInstance().removeKey();
|
||||
hasValidLicenseKey = false;
|
||||
message = null;
|
||||
EventManager.getInstance().emit(
|
||||
PluginEvent.LICENSE_KEY_VALIDATION_CHANGE,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
function getMessageClassName(message: Message | null) {
|
||||
|
|
@ -107,12 +99,16 @@
|
|||
{/if}
|
||||
</div>
|
||||
<div class="setting-item-control">
|
||||
{#if isDeviceRegistered === false}
|
||||
<input type="text" maxlength="8" on:input={handleInputChange} />
|
||||
{#if hasValidLicenseKey === false}
|
||||
<input
|
||||
type="text"
|
||||
maxlength={LICENSE_KEY_SIZE}
|
||||
on:input={handleInputChange}
|
||||
/>
|
||||
{/if}
|
||||
{#if isDeviceRegistered === true}
|
||||
<button class="mod-destructive" on:click={handleButtonClick}
|
||||
>Unregister device</button
|
||||
{#if hasValidLicenseKey === true}
|
||||
<button class="mod-destructive" on:click={handleRemoveButtonClick}
|
||||
>Remove key</button
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
import Logger from "js-logger";
|
||||
import { generateRandomDeviceId } from "./random";
|
||||
|
||||
const LOCAL_STORAGE_KEY = "vault-explorer-id";
|
||||
|
||||
/**
|
||||
* Loads the device id from local storage or creates a new one if it doesn't exist
|
||||
* @returns The device id
|
||||
*/
|
||||
export const loadDeviceId = (): void => {
|
||||
Logger.trace({ fileName: "license-utils.ts", functionName: "loadDeviceId", message: "called" });
|
||||
|
||||
const deviceId = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (deviceId !== null) {
|
||||
Logger.trace({ fileName: "license-utils.ts", functionName: "loadDeviceId", message: "found device id" });
|
||||
} else {
|
||||
Logger.trace({ fileName: "license-utils.ts", functionName: "loadDeviceId", message: "creating device id" });
|
||||
const newDeviceId = generateRandomDeviceId();
|
||||
localStorage.setItem(LOCAL_STORAGE_KEY, newDeviceId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the device id from local storage
|
||||
* @returns The device id
|
||||
* @throws Error if loadDeviceId() has not been called
|
||||
*/
|
||||
export const readDeviceId = (): string => {
|
||||
Logger.trace({ fileName: "license-utils.ts", functionName: "readDeviceId", message: "called" });
|
||||
const deviceId = localStorage.getItem(LOCAL_STORAGE_KEY);
|
||||
if (deviceId === null) {
|
||||
throw new Error("Device id not found. Please call loadDeviceId() first.");
|
||||
}
|
||||
return deviceId;
|
||||
}
|
||||
|
|
@ -1,257 +1,138 @@
|
|||
import Logger from "js-logger";
|
||||
import { requestUrl } from "obsidian";
|
||||
import { readDeviceId } from "./device-id-utils";
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export const LICENSE_KEY_LENGTH = 8;
|
||||
import crypto from "crypto";
|
||||
|
||||
const LOCAL_STORAGE_LICENSE_KEY = "vault-explorer-license-key";
|
||||
|
||||
const LOCAL_STORAGE_DEVICE_REGISTERED = "vault-explorer-device-registration";
|
||||
const PUBLIC_KEY_PEM = `
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MCowBQYDK2VwAyEAO539qAsgBzbukUNDuOtPZKXNj8MSXvt3zS1ci4plDBA=
|
||||
-----END PUBLIC KEY-----
|
||||
`;
|
||||
|
||||
export default class License {
|
||||
private isDeviceRegistered: boolean;
|
||||
private licenseKey: string;
|
||||
private responseMessage: string;
|
||||
private isDeviceRegisteredStore = writable<boolean>();
|
||||
private hasValidKey: boolean;
|
||||
private hasValidKeyStore = writable<boolean>();
|
||||
|
||||
private static instance: License;
|
||||
|
||||
constructor() {
|
||||
const storedDeviceRegistered = this.getStoredDeviceRegistered();
|
||||
this.isDeviceRegistered = storedDeviceRegistered;
|
||||
this.isDeviceRegisteredStore.set(storedDeviceRegistered);
|
||||
Logger.debug({ fileName: "license.ts", functionName: "constructor", message: "loaded stored device registration", }, storedDeviceRegistered);
|
||||
|
||||
this.responseMessage = "";
|
||||
this.licenseKey = "";
|
||||
this.hasValidKey = false;
|
||||
this.hasValidKeyStore.set(false);
|
||||
}
|
||||
|
||||
async loadStoredKey() {
|
||||
const storedKey = this.getStoredLicenseKey();
|
||||
this.licenseKey = storedKey;
|
||||
Logger.debug({ fileName: "license.ts", functionName: "constructor", message: "loaded stored license key" }, storedKey);
|
||||
if (storedKey) {
|
||||
const isValid = await this.validateKey(storedKey);
|
||||
|
||||
this.licenseKey = storedKey;
|
||||
this.hasValidKey = isValid;
|
||||
this.hasValidKeyStore.set(isValid);
|
||||
}
|
||||
}
|
||||
|
||||
async registerDevice(licenseKey: string) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "registerDevice", message: "called" });
|
||||
async addKey(licenseKey: string) {
|
||||
Logger.trace({
|
||||
fileName: "license.ts",
|
||||
functionName: "addKey",
|
||||
message: "called",
|
||||
});
|
||||
|
||||
const deviceId = readDeviceId();
|
||||
const result = await this.postRegisterDevice(licenseKey, deviceId);
|
||||
const result = await this.validateKey(licenseKey);
|
||||
if (result) {
|
||||
this.updateDeviceRegistered(true);
|
||||
this.updateLicenseKey(licenseKey);
|
||||
this.setStoredKey(licenseKey);
|
||||
this.hasValidKeyStore.set(true);
|
||||
this.hasValidKey = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async unregisterDevice() {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "unregisterDevice", message: "called" });
|
||||
/**
|
||||
* Verify the licenseKey using the public key.
|
||||
* @param signature- The licenseKey to verify. This is created by signing a file with the private key.
|
||||
*/
|
||||
async validateKey(licenseKey: string) {
|
||||
Logger.trace({
|
||||
fileName: "license.ts",
|
||||
functionName: "validateKey",
|
||||
message: "called",
|
||||
});
|
||||
|
||||
const deviceId = readDeviceId();
|
||||
const result = await this.postUnregisterDevice(this.licenseKey, deviceId);
|
||||
if (result) {
|
||||
this.updateLicenseKey("");
|
||||
this.updateDeviceRegistered(false);
|
||||
try {
|
||||
// Decode Base64 to buffer
|
||||
const decodedBuffer = Buffer.from(licenseKey, "base64");
|
||||
const decodedString = decodedBuffer.toString("utf-8");
|
||||
const split = decodedString.split("|");
|
||||
|
||||
const data = split[0];
|
||||
const signatureBase64 = split[1];
|
||||
|
||||
const dataBuffer = Buffer.from(data);
|
||||
const signatureBuffer = Buffer.from(signatureBase64, "base64");
|
||||
|
||||
const verify = crypto.createVerify("SHA256");
|
||||
verify.update(data);
|
||||
verify.end();
|
||||
|
||||
return crypto.verify(
|
||||
null,
|
||||
dataBuffer,
|
||||
{
|
||||
key: PUBLIC_KEY_PEM,
|
||||
format: "pem",
|
||||
type: "spki",
|
||||
},
|
||||
signatureBuffer
|
||||
);
|
||||
} catch (err) {
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async verifyLicense() {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "verifyLicense", message: "called" });
|
||||
removeKey() {
|
||||
Logger.trace({
|
||||
fileName: "license.ts",
|
||||
functionName: "removeKey",
|
||||
message: "called",
|
||||
});
|
||||
|
||||
if (this.licenseKey === "") {
|
||||
Logger.debug({ fileName: "license.ts", functionName: "verifyLicense", message: "no license key set. returning..." });
|
||||
return;
|
||||
} else if (this.licenseKey.length !== LICENSE_KEY_LENGTH) {
|
||||
Logger.debug({ fileName: "license.ts", functionName: "verifyLicense", message: "license key is not the correct length. returning..." });
|
||||
return;
|
||||
}
|
||||
this.setStoredKey(null);
|
||||
this.hasValidKeyStore.set(false);
|
||||
this.hasValidKey = false;
|
||||
}
|
||||
|
||||
const deviceId = readDeviceId();
|
||||
|
||||
const result = await this.postVerifyDevice(this.licenseKey, deviceId);
|
||||
if (result) {
|
||||
this.updateDeviceRegistered(true);
|
||||
private setStoredKey(value: string | null) {
|
||||
Logger.trace({
|
||||
fileName: "license.ts",
|
||||
functionName: "setStoredKey",
|
||||
message: "called",
|
||||
});
|
||||
if (value !== null) {
|
||||
localStorage.setItem(LOCAL_STORAGE_LICENSE_KEY, value);
|
||||
} else {
|
||||
this.updateDeviceRegistered(false);
|
||||
localStorage.removeItem(LOCAL_STORAGE_LICENSE_KEY);
|
||||
}
|
||||
}
|
||||
|
||||
private async postVerifyDevice(licenseKey: string, deviceId: string) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "postVerifyDevice", message: "called" });
|
||||
try {
|
||||
const response = await requestUrl({
|
||||
url: "https://api.vaultexplorer.com/licenses/verify",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
licenseKey,
|
||||
deviceId,
|
||||
}),
|
||||
});
|
||||
const body = response.json;
|
||||
Logger.debug({ fileName: "license.ts", functionName: "postVerifyDevice", message: "response" }, body);
|
||||
return true;
|
||||
} catch (err: unknown) {
|
||||
const error = err as Error;
|
||||
Logger.error({ fileName: "license.ts", functionName: "postVerifyDevice", message: "error verifying device" }, error.message);
|
||||
|
||||
if (error.message.contains("net::ERR_INTERNET_DISCONNECTED")) {
|
||||
const deviceRegistered = License.getInstance().getIsDeviceRegistered();
|
||||
Logger.debug({ fileName: "license.ts", functionName: "postVerifyDevice", message: "returning last deviceRegistered state", }, deviceRegistered);
|
||||
return deviceRegistered;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
private async postRegisterDevice(licenseKey: string, deviceId: string) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "postRegisterDevice", message: "called" });
|
||||
try {
|
||||
const response = await requestUrl({
|
||||
url: "https://api.vaultexplorer.com/licenses/register",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
licenseKey,
|
||||
deviceId,
|
||||
})
|
||||
});
|
||||
const body = response.json;
|
||||
Logger.debug({ fileName: "license.ts", functionName: "postRegisterDevice", message: "response" }, body);
|
||||
this.responseMessage = "Device successfully registered."
|
||||
return true;
|
||||
|
||||
} catch (err: unknown) {
|
||||
const error = err as Error;
|
||||
let message = "";
|
||||
if (error.message.contains("net::ERR_INTERNET_DISCONNECTED")) {
|
||||
message = "Internet is disconnected. Please try again"
|
||||
} else if (error.message.contains("429")) {
|
||||
message = "Too many requests. Try again later"
|
||||
} else if (error.message.contains("404")) {
|
||||
message = "Invalid license key"
|
||||
} else if (error.message.contains("400")) {
|
||||
message = "Device already registered to this license"
|
||||
} else if (error.message.contains("402")) {
|
||||
message = "Maximum number of devices reached for this license key"
|
||||
} else if (error.message.contains("502")) {
|
||||
message = "Server is offline. Please try again later"
|
||||
} else {
|
||||
message = "Server error. Please open an issue on GitHub"
|
||||
}
|
||||
this.responseMessage = message;
|
||||
|
||||
Logger.error({ fileName: "license.ts", functionName: "postRegisterDevice", message: "error registering device" }, error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private async postUnregisterDevice(licenseKey: string, deviceId: string) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "postUnregisterDevice", message: "called" });
|
||||
try {
|
||||
const response = await requestUrl({
|
||||
url: "https://api.vaultexplorer.com/licenses/unregister",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({
|
||||
licenseKey,
|
||||
deviceId,
|
||||
})
|
||||
});
|
||||
const body = response.json;
|
||||
Logger.debug({ fileName: "license.ts", functionName: "postUnregisterDevice", message: "response" }, body);
|
||||
this.responseMessage = "";
|
||||
return true;
|
||||
|
||||
} catch (err: unknown) {
|
||||
const error = err as Error;
|
||||
|
||||
let message = "";
|
||||
if (error.message.contains("net::ERR_INTERNET_DISCONNECTED")) {
|
||||
message = "Internet is disconnected. Please try again"
|
||||
} else if (error.message.contains("429")) {
|
||||
message = "Too many requests. Try again later"
|
||||
} else if (error.message.contains("400")) {
|
||||
message = "Device is not connected to a license key";
|
||||
} else if (error.message.contains("502")) {
|
||||
message = "Server is offline. Please try again later"
|
||||
} else {
|
||||
message = "Server error. Please open an issue on GitHub"
|
||||
}
|
||||
this.responseMessage = message;
|
||||
|
||||
|
||||
Logger.error({ fileName: "license.ts", functionName: "postUnregisterDevice", message: "error unregistering device" }, error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class licenseKey and updates local storage
|
||||
* @param value - The license key
|
||||
*/
|
||||
private updateLicenseKey(value: string) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "updateLicenseKey", message: "called" });
|
||||
this.licenseKey = value;
|
||||
this.setStoredLicenseKey(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the class registration flag and updates local storage
|
||||
* @param value - The registration status of the device
|
||||
*/
|
||||
private updateDeviceRegistered(value: boolean) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "updateDeviceRegistered", message: "called" });
|
||||
this.isDeviceRegistered = value;
|
||||
this.isDeviceRegisteredStore.set(value);
|
||||
this.setStoredDeviceRegistered(value);
|
||||
}
|
||||
|
||||
private setStoredLicenseKey(value: string) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "setStoredLicenseKey", message: "called" });
|
||||
localStorage.setItem(LOCAL_STORAGE_LICENSE_KEY, value);
|
||||
}
|
||||
|
||||
private getStoredLicenseKey() {
|
||||
return localStorage.getItem(LOCAL_STORAGE_LICENSE_KEY) ?? ""
|
||||
return localStorage.getItem(LOCAL_STORAGE_LICENSE_KEY);
|
||||
}
|
||||
|
||||
private getStoredDeviceRegistered() {
|
||||
const value = localStorage.getItem(LOCAL_STORAGE_DEVICE_REGISTERED);
|
||||
if (value) {
|
||||
return value === "true";
|
||||
}
|
||||
return false;
|
||||
getHasValidKey() {
|
||||
return this.hasValidKey;
|
||||
}
|
||||
|
||||
setStoredDeviceRegistered(value: boolean) {
|
||||
Logger.trace({ fileName: "license.ts", functionName: "setStoredDeviceRegistered", message: "called" });
|
||||
localStorage.setItem(LOCAL_STORAGE_DEVICE_REGISTERED, value.toString());
|
||||
getHasValidKeyStore() {
|
||||
return this.hasValidKeyStore;
|
||||
}
|
||||
|
||||
getIsDeviceRegistered() {
|
||||
return this.isDeviceRegistered;
|
||||
}
|
||||
|
||||
getIsDeviceRegisteredStore() {
|
||||
return this.isDeviceRegisteredStore
|
||||
}
|
||||
|
||||
|
||||
getLicenseKey() {
|
||||
return this.licenseKey;
|
||||
}
|
||||
|
||||
getResponseMessage() {
|
||||
return this.responseMessage;
|
||||
}
|
||||
|
||||
static getInstance() {
|
||||
if (!this.instance) {
|
||||
this.instance = new License();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,8 @@ import { customAlphabet } from "nanoid";
|
|||
//An alphabet that excludes characters that are easily confused with each other
|
||||
// Excludes: 0, O, I, l
|
||||
const nanoid = customAlphabet(
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz");
|
||||
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
|
||||
);
|
||||
|
||||
/**
|
||||
* Generates a random id
|
||||
|
|
@ -13,14 +14,4 @@ const nanoid = customAlphabet(
|
|||
*/
|
||||
export const generateRandomId = () => {
|
||||
return nanoid(16);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random vault id
|
||||
* base58: 58 characters
|
||||
* 12 characters: 58^12 = 1.4e+21
|
||||
* @returns A random string of length 12
|
||||
*/
|
||||
export const generateRandomDeviceId = () => {
|
||||
return nanoid(12);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -30,20 +30,8 @@
|
|||
{
|
||||
"id": "A3PgwC3AaYu1XqDn",
|
||||
"name": "Group 1",
|
||||
"rules": [
|
||||
{
|
||||
"id": "EiihU98U3T6b6UNr",
|
||||
"type": "property",
|
||||
"propertyType": "text",
|
||||
"propertyName": "",
|
||||
"operator": "and",
|
||||
"isEnabled": true,
|
||||
"condition": "is",
|
||||
"value": "",
|
||||
"matchWhenPropertyDNE": false
|
||||
}
|
||||
],
|
||||
"isEnabled": false,
|
||||
"rules": [],
|
||||
"isEnabled": true,
|
||||
"isSticky": false
|
||||
}
|
||||
]
|
||||
|
|
@ -104,6 +92,6 @@
|
|||
"feed"
|
||||
],
|
||||
"configDir": ".vaultexplorer",
|
||||
"pluginVersion": "1.35.0",
|
||||
"pluginVersion": "1.36.0",
|
||||
"logLevel": "trace"
|
||||
}
|
||||
|
|
@ -122,5 +122,6 @@
|
|||
"1.34.2": "1.4.13",
|
||||
"1.34.3": "1.4.13",
|
||||
"1.35.0": "1.4.13",
|
||||
"1.35.1": "1.4.13"
|
||||
"1.35.1": "1.4.13",
|
||||
"1.36.0": "1.4.13"
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue