update license validation & urls

Signed-off-by: FTCHD <144691102+FTCHD@users.noreply.github.com>
This commit is contained in:
FTCHD
2025-08-14 22:46:14 +02:00
parent cc3b35a4ea
commit 8c9ebecd67
4 changed files with 102 additions and 81 deletions
+11 -9
View File
@@ -1,5 +1,6 @@
import { invoke } from '@tauri-apps/api/core'
import { fetch } from '@tauri-apps/plugin-http'
import { platform } from '@tauri-apps/plugin-os'
import { usePersistedStore } from './store'
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.')
}
const validationResponse = await fetch('https://rcloneui.com/api/v1/validate', {
const validationResponse = await fetch('https://rcloneui.com/api/v2/validate', {
method: 'POST',
body: JSON.stringify({
licenseKey,
id,
platform: platform(),
}),
})
.then((r) => r.json())
@@ -49,21 +51,21 @@ export async function validateLicense(licenseKey: string) {
console.log('[validateLicense] license validated')
}
export async function revokeLicense(licenseKey: string) {
console.log('[revokeLicense]')
export async function revokeMachineLicense(licenseKey: string) {
console.log('[revokeMachineLicense]')
let id
try {
id = await invoke('get_uid')
} catch (e) {
console.error('[revokeLicense] failed to build unique identifier')
console.error('[revokeMachineLicense] failed to build unique identifier')
console.error(JSON.stringify(e))
throw new Error('Failed to build unique identifier. Please try again later.')
}
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.')
}
@@ -76,22 +78,22 @@ export async function revokeLicense(licenseKey: string) {
})
.then((r) => r.json())
.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))
throw new Error('Failed to revoke license. Are you connected to the internet?')
})
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)
}
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.')
}
usePersistedStore.setState({ licenseKey: undefined, licenseValid: false })
console.log('[revokeLicense] license revoked')
console.log('[revokeMachineLicense] license revoked')
}
+7 -9
View File
@@ -73,24 +73,22 @@ async function validateInstance() {
try {
await validateLicense(licenseKey)
} catch (e) {
usePersistedStore.setState({ licenseValid: false })
if (e instanceof Error) {
await ask(e.message, {
title: 'Error',
await message(e.message, {
title: 'Error Validating License',
kind: 'error',
okLabel: 'Exit',
cancelLabel: '',
okLabel: 'OK',
})
await exit(0)
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',
kind: 'error',
okLabel: 'Exit',
cancelLabel: '',
okLabel: 'OK',
})
await exit(0)
}
}
+24
View File
@@ -285,8 +285,32 @@
{
"url": "https://github.com/**"
},
{
"url": "https://raw.githubusercontent.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
View File
@@ -13,6 +13,7 @@ import {
Tab,
Tabs,
Textarea,
cn,
} from '@heroui/react'
import { getTauriVersion, getVersion as getUiVersion } from '@tauri-apps/api/app'
import {
@@ -45,8 +46,14 @@ import {
ServerIcon,
Trash2Icon,
} from 'lucide-react'
import { useCallback, useEffect, useState } from 'react'
import { revokeLicense, validateLicense } from '../../lib/license'
import {
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 { getConfigPath, getDefaultPaths } from '../../lib/rclone/common'
import { usePersistedStore, useStore } from '../../lib/store'
@@ -58,6 +65,15 @@ import RemoteCreateDrawer from '../components/RemoteCreateDrawer'
import RemoteDefaultsDrawer from '../components/RemoteDefaultsDrawer'
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() {
const settingsPass = usePersistedStore((state) => state.settingsPass)
@@ -550,13 +566,30 @@ function LicenseSection() {
const [isActivating, setIsActivating] = useState(false)
const [licenseKeyInput, setLicenseKeyInput] = useState('')
const [showPricingTable, setShowPricingTable] = useState(false)
useEffect(() => {
setLicenseKeyInput(licenseKey || '')
setIsLicenseEditable(!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 (
<div className="flex flex-col gap-10">
<div className="flex flex-col gap-8">
<BaseHeader title="License" />
<div className="flex flex-row justify-center w-full gap-8 px-8">
@@ -654,7 +687,7 @@ function LicenseSection() {
setIsRevoking(true)
try {
await revokeLicense(licenseKeyInput)
await revokeMachineLicense(licenseKeyInput)
} catch (e) {
if (e instanceof Error) {
await ask(e.message, {
@@ -689,65 +722,17 @@ function LicenseSection() {
</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">Buy</h3>
<p className="text-xs text-neutral-500 text-end">
Includes access to future features and updates.
</p>
</div>
<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
className={cn(
'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'
)}
>
<stripe-pricing-table
pricing-table-id="prctbl_1RvnumE0hPdsH0naQ6l8Rd86"
publishable-key="pk_live_51QmUqyE0hPdsH0naBICHzb0j5O5eTKyYnY72nOaS6aT99y3EBeCOyeihI2xX05D6cczifqPsX6vHhor8ozSblXPl00LqNwMxBE"
/>
</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>
)
}
@@ -917,6 +902,8 @@ function RemotesSection() {
}
function ConfigSection() {
const licenseValid = usePersistedStore((state) => state.licenseValid)
const configFiles = usePersistedStore((state) => state.configFiles)
const activeConfigFile = usePersistedStore((state) => state.activeConfigFile)
@@ -938,10 +925,20 @@ function ConfigSection() {
</DropdownTrigger>
<DropdownMenu
onAction={(key) => {
setTimeout(() => {
setTimeout(async () => {
if (key === 'import') {
setIsCreateDrawerOpen(true)
} else {
if (!licenseValid) {
await message(
'Community version does not support syncing configs.',
{
title: 'Missing license',
kind: 'error',
}
)
return
}
setIsSyncDrawerOpen(true)
}
}, 100)