update license validation & urls
Signed-off-by: FTCHD <144691102+FTCHD@users.noreply.github.com>
This commit is contained in:
+11
-9
@@ -1,5 +1,6 @@
|
|||||||
import { invoke } from '@tauri-apps/api/core'
|
import { invoke } from '@tauri-apps/api/core'
|
||||||
import { fetch } from '@tauri-apps/plugin-http'
|
import { fetch } from '@tauri-apps/plugin-http'
|
||||||
|
import { platform } from '@tauri-apps/plugin-os'
|
||||||
import { usePersistedStore } from './store'
|
import { usePersistedStore } from './store'
|
||||||
|
|
||||||
export async function validateLicense(licenseKey: string) {
|
export async function validateLicense(licenseKey: string) {
|
||||||
@@ -20,11 +21,12 @@ export async function validateLicense(licenseKey: string) {
|
|||||||
throw new Error('Failed to build unique identifier. Please try again later.')
|
throw new Error('Failed to build unique identifier. Please try again later.')
|
||||||
}
|
}
|
||||||
|
|
||||||
const validationResponse = await fetch('https://rcloneui.com/api/v1/validate', {
|
const validationResponse = await fetch('https://rcloneui.com/api/v2/validate', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
licenseKey,
|
licenseKey,
|
||||||
id,
|
id,
|
||||||
|
platform: platform(),
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
@@ -49,21 +51,21 @@ export async function validateLicense(licenseKey: string) {
|
|||||||
console.log('[validateLicense] license validated')
|
console.log('[validateLicense] license validated')
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function revokeLicense(licenseKey: string) {
|
export async function revokeMachineLicense(licenseKey: string) {
|
||||||
console.log('[revokeLicense]')
|
console.log('[revokeMachineLicense]')
|
||||||
|
|
||||||
let id
|
let id
|
||||||
|
|
||||||
try {
|
try {
|
||||||
id = await invoke('get_uid')
|
id = await invoke('get_uid')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[revokeLicense] failed to build unique identifier')
|
console.error('[revokeMachineLicense] failed to build unique identifier')
|
||||||
console.error(JSON.stringify(e))
|
console.error(JSON.stringify(e))
|
||||||
throw new Error('Failed to build unique identifier. Please try again later.')
|
throw new Error('Failed to build unique identifier. Please try again later.')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
console.error('[revokeLicense] missing unique identifier')
|
console.error('[revokeMachineLicense] missing unique identifier')
|
||||||
throw new Error('Failed to build unique identifier. Please try again later.')
|
throw new Error('Failed to build unique identifier. Please try again later.')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,22 +78,22 @@ export async function revokeLicense(licenseKey: string) {
|
|||||||
})
|
})
|
||||||
.then((r) => r.json())
|
.then((r) => r.json())
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error('[revokeLicense] failed to revoke license, fetch failed')
|
console.error('[revokeMachineLicense] failed to revoke license, fetch failed')
|
||||||
console.error(JSON.stringify(e))
|
console.error(JSON.stringify(e))
|
||||||
throw new Error('Failed to revoke license. Are you connected to the internet?')
|
throw new Error('Failed to revoke license. Are you connected to the internet?')
|
||||||
})
|
})
|
||||||
|
|
||||||
if (revocationResponse.error) {
|
if (revocationResponse.error) {
|
||||||
console.error('[revokeLicense] failed to revoke license, has error response')
|
console.error('[revokeMachineLicense] failed to revoke license, has error response')
|
||||||
throw new Error(revocationResponse.error)
|
throw new Error(revocationResponse.error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!revocationResponse.revoked) {
|
if (!revocationResponse.revoked) {
|
||||||
console.error('[revokeLicense] failed to revoke license, missing revoked response')
|
console.error('[revokeMachineLicense] failed to revoke license, missing revoked response')
|
||||||
throw new Error('Failed to revoke license. Please check your license key and try again.')
|
throw new Error('Failed to revoke license. Please check your license key and try again.')
|
||||||
}
|
}
|
||||||
|
|
||||||
usePersistedStore.setState({ licenseKey: undefined, licenseValid: false })
|
usePersistedStore.setState({ licenseKey: undefined, licenseValid: false })
|
||||||
|
|
||||||
console.log('[revokeLicense] license revoked')
|
console.log('[revokeMachineLicense] license revoked')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,24 +73,22 @@ async function validateInstance() {
|
|||||||
try {
|
try {
|
||||||
await validateLicense(licenseKey)
|
await validateLicense(licenseKey)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
usePersistedStore.setState({ licenseValid: false })
|
||||||
|
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
await ask(e.message, {
|
await message(e.message, {
|
||||||
title: 'Error',
|
title: 'Error Validating License',
|
||||||
kind: 'error',
|
kind: 'error',
|
||||||
okLabel: 'Exit',
|
okLabel: 'OK',
|
||||||
cancelLabel: '',
|
|
||||||
})
|
})
|
||||||
await exit(0)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
await ask('An error occurred while validating your license. Please try again.', {
|
await message('An error occurred while validating your license. Please try again.', {
|
||||||
title: 'Error',
|
title: 'Error',
|
||||||
kind: 'error',
|
kind: 'error',
|
||||||
okLabel: 'Exit',
|
okLabel: 'OK',
|
||||||
cancelLabel: '',
|
|
||||||
})
|
})
|
||||||
await exit(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -285,8 +285,32 @@
|
|||||||
{
|
{
|
||||||
"url": "https://github.com/**"
|
"url": "https://github.com/**"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"url": "https://raw.githubusercontent.com/**"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "https://rcloneui.com/**"
|
"url": "https://rcloneui.com/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://stripe.com/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://buy.stripe.com/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://checkout.stripe.com/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://js.stripe.com/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://donate.stripe.com/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://payments.stripe.com/**"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://checkout.link.com/**"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
+60
-63
@@ -13,6 +13,7 @@ import {
|
|||||||
Tab,
|
Tab,
|
||||||
Tabs,
|
Tabs,
|
||||||
Textarea,
|
Textarea,
|
||||||
|
cn,
|
||||||
} from '@heroui/react'
|
} from '@heroui/react'
|
||||||
import { getTauriVersion, getVersion as getUiVersion } from '@tauri-apps/api/app'
|
import { getTauriVersion, getVersion as getUiVersion } from '@tauri-apps/api/app'
|
||||||
import {
|
import {
|
||||||
@@ -45,8 +46,14 @@ import {
|
|||||||
ServerIcon,
|
ServerIcon,
|
||||||
Trash2Icon,
|
Trash2Icon,
|
||||||
} from 'lucide-react'
|
} from 'lucide-react'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import {
|
||||||
import { revokeLicense, validateLicense } from '../../lib/license'
|
type DetailedHTMLProps,
|
||||||
|
type HTMLAttributes,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} from 'react'
|
||||||
|
import { revokeMachineLicense, validateLicense } from '../../lib/license'
|
||||||
import { deleteRemote, getVersion as getCliVersion, getVersion } from '../../lib/rclone/api'
|
import { deleteRemote, getVersion as getCliVersion, getVersion } from '../../lib/rclone/api'
|
||||||
import { getConfigPath, getDefaultPaths } from '../../lib/rclone/common'
|
import { getConfigPath, getDefaultPaths } from '../../lib/rclone/common'
|
||||||
import { usePersistedStore, useStore } from '../../lib/store'
|
import { usePersistedStore, useStore } from '../../lib/store'
|
||||||
@@ -58,6 +65,15 @@ import RemoteCreateDrawer from '../components/RemoteCreateDrawer'
|
|||||||
import RemoteDefaultsDrawer from '../components/RemoteDefaultsDrawer'
|
import RemoteDefaultsDrawer from '../components/RemoteDefaultsDrawer'
|
||||||
import RemoteEditDrawer from '../components/RemoteEditDrawer'
|
import RemoteEditDrawer from '../components/RemoteEditDrawer'
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
// biome-ignore lint/style/noNamespace: <explanation>
|
||||||
|
namespace JSX {
|
||||||
|
interface IntrinsicElements {
|
||||||
|
'stripe-pricing-table': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function Settings() {
|
function Settings() {
|
||||||
const settingsPass = usePersistedStore((state) => state.settingsPass)
|
const settingsPass = usePersistedStore((state) => state.settingsPass)
|
||||||
|
|
||||||
@@ -550,13 +566,30 @@ function LicenseSection() {
|
|||||||
const [isActivating, setIsActivating] = useState(false)
|
const [isActivating, setIsActivating] = useState(false)
|
||||||
const [licenseKeyInput, setLicenseKeyInput] = useState('')
|
const [licenseKeyInput, setLicenseKeyInput] = useState('')
|
||||||
|
|
||||||
|
const [showPricingTable, setShowPricingTable] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLicenseKeyInput(licenseKey || '')
|
setLicenseKeyInput(licenseKey || '')
|
||||||
setIsLicenseEditable(!licenseKey)
|
setIsLicenseEditable(!licenseKey)
|
||||||
}, [licenseKey])
|
}, [licenseKey])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const script = document.createElement('script')
|
||||||
|
script.src = 'https://js.stripe.com/v3/pricing-table.js'
|
||||||
|
script.async = true
|
||||||
|
document.body.appendChild(script)
|
||||||
|
const cancelTimeout = setTimeout(() => {
|
||||||
|
setShowPricingTable(true)
|
||||||
|
}, 1000)
|
||||||
|
return () => {
|
||||||
|
clearTimeout(cancelTimeout)
|
||||||
|
setShowPricingTable(false)
|
||||||
|
document.body.removeChild(script)
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col gap-10">
|
<div className="flex flex-col gap-8">
|
||||||
<BaseHeader title="License" />
|
<BaseHeader title="License" />
|
||||||
|
|
||||||
<div className="flex flex-row justify-center w-full gap-8 px-8">
|
<div className="flex flex-row justify-center w-full gap-8 px-8">
|
||||||
@@ -654,7 +687,7 @@ function LicenseSection() {
|
|||||||
|
|
||||||
setIsRevoking(true)
|
setIsRevoking(true)
|
||||||
try {
|
try {
|
||||||
await revokeLicense(licenseKeyInput)
|
await revokeMachineLicense(licenseKeyInput)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (e instanceof Error) {
|
if (e instanceof Error) {
|
||||||
await ask(e.message, {
|
await ask(e.message, {
|
||||||
@@ -689,65 +722,17 @@ function LicenseSection() {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-row justify-center w-full gap-8 px-8">
|
<div
|
||||||
<div className="flex flex-col items-end w-2/6 gap-2 bg-transparent-500">
|
className={cn(
|
||||||
<h3 className="font-medium">Buy</h3>
|
'w-full overflow-hidden border-0 border-red-500 left-28 h-[470px] opacity-0 transition-opacity duration-300 ease-in-out',
|
||||||
|
showPricingTable && 'opacity-100'
|
||||||
<p className="text-xs text-neutral-500 text-end">
|
)}
|
||||||
Includes access to future features and updates.
|
>
|
||||||
</p>
|
<stripe-pricing-table
|
||||||
</div>
|
pricing-table-id="prctbl_1RvnumE0hPdsH0naQ6l8Rd86"
|
||||||
|
publishable-key="pk_live_51QmUqyE0hPdsH0naBICHzb0j5O5eTKyYnY72nOaS6aT99y3EBeCOyeihI2xX05D6cczifqPsX6vHhor8ozSblXPl00LqNwMxBE"
|
||||||
<div className="flex flex-col w-4/6 gap-3 bg-transparent-500">
|
/>
|
||||||
<Button
|
|
||||||
size="lg"
|
|
||||||
fullWidth={true}
|
|
||||||
color="primary"
|
|
||||||
variant="shadow"
|
|
||||||
onPress={async () => {
|
|
||||||
await openUrl('https://buy.stripe.com/3csbKIb1t433a8obII')
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Lifetime License — $7
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* <div className="flex flex-row justify-center w-full gap-8 px-8">
|
|
||||||
<div className="flex flex-col items-end w-2/6 gap-2 bg-transparent-500">
|
|
||||||
<h3 className="font-medium">Features</h3>
|
|
||||||
<p className="text-xs text-neutral-500 text-end">What you get with a license</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col w-4/6 gap-2 bg-transparent-500">
|
|
||||||
<Card className="border-none bg-background/60 dark:bg-default-100/60">
|
|
||||||
<CardBody>
|
|
||||||
<ul className="flex flex-col gap-3">
|
|
||||||
<li className="flex items-center gap-2">
|
|
||||||
<CheckIcon className="w-5 h-5 text-green-500" />
|
|
||||||
<span>Work with more than 3 remotes</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-2">
|
|
||||||
<CheckIcon className="w-5 h-5 text-green-500" />
|
|
||||||
<span>Runs on up to 5 devices</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-2">
|
|
||||||
<CheckIcon className="w-5 h-5 text-green-500" />
|
|
||||||
<span>File Commander</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-2">
|
|
||||||
<CheckIcon className="w-5 h-5 text-green-500" />
|
|
||||||
<span>Mobile Client</span>
|
|
||||||
</li>
|
|
||||||
<li className="flex items-center gap-2">
|
|
||||||
<CheckIcon className="w-5 h-5 text-green-500" />
|
|
||||||
<span>Supporting Open Source</span>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</CardBody>
|
|
||||||
</Card>
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -917,6 +902,8 @@ function RemotesSection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function ConfigSection() {
|
function ConfigSection() {
|
||||||
|
const licenseValid = usePersistedStore((state) => state.licenseValid)
|
||||||
|
|
||||||
const configFiles = usePersistedStore((state) => state.configFiles)
|
const configFiles = usePersistedStore((state) => state.configFiles)
|
||||||
const activeConfigFile = usePersistedStore((state) => state.activeConfigFile)
|
const activeConfigFile = usePersistedStore((state) => state.activeConfigFile)
|
||||||
|
|
||||||
@@ -938,10 +925,20 @@ function ConfigSection() {
|
|||||||
</DropdownTrigger>
|
</DropdownTrigger>
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
onAction={(key) => {
|
onAction={(key) => {
|
||||||
setTimeout(() => {
|
setTimeout(async () => {
|
||||||
if (key === 'import') {
|
if (key === 'import') {
|
||||||
setIsCreateDrawerOpen(true)
|
setIsCreateDrawerOpen(true)
|
||||||
} else {
|
} else {
|
||||||
|
if (!licenseValid) {
|
||||||
|
await message(
|
||||||
|
'Community version does not support syncing configs.',
|
||||||
|
{
|
||||||
|
title: 'Missing license',
|
||||||
|
kind: 'error',
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
setIsSyncDrawerOpen(true)
|
setIsSyncDrawerOpen(true)
|
||||||
}
|
}
|
||||||
}, 100)
|
}, 100)
|
||||||
|
|||||||
Reference in New Issue
Block a user