This commit is contained in:
@@ -41,7 +41,7 @@ tauri-plugin-log = "2"
|
||||
tauri-plugin-fs = "2"
|
||||
tauri-plugin-dialog = "2"
|
||||
tauri-plugin-os = "2"
|
||||
tauri-plugin-http = "2"
|
||||
tauri-plugin-http = { version = "2", features = ["dangerous-settings"] }
|
||||
tauri-plugin-shell = "2"
|
||||
tauri-plugin-process = "2"
|
||||
tauri-plugin-oauth = "2"
|
||||
|
||||
@@ -87,6 +87,12 @@
|
||||
},
|
||||
{
|
||||
"url": "https://translate.googleapis.com"
|
||||
},
|
||||
{
|
||||
"url": "http://*:*"
|
||||
},
|
||||
{
|
||||
"url": "https://*:*"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -16,6 +16,7 @@ import { getOSPlatform } from '@/utils/misc';
|
||||
type Option = {
|
||||
value: string;
|
||||
label: string;
|
||||
disabled?: boolean;
|
||||
};
|
||||
|
||||
type SelectProps = {
|
||||
@@ -43,8 +44,8 @@ const StyledSelect: React.FC<SelectProps> = ({
|
||||
)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{options.map(({ value, label }) => (
|
||||
<option key={value} value={value}>
|
||||
{options.map(({ value, label, disabled = false }) => (
|
||||
<option key={value} value={value} disabled={disabled}>
|
||||
{label}
|
||||
</option>
|
||||
))}
|
||||
@@ -83,6 +84,12 @@ export const KOSyncSettingsWindow: React.FC = () => {
|
||||
|
||||
// Get the OS name once
|
||||
useEffect(() => {
|
||||
const formatOsName = (name: string): string => {
|
||||
if (!name) return '';
|
||||
if (name.toLowerCase() === 'macos') return 'macOS';
|
||||
return name.charAt(0).toUpperCase() + name.slice(1);
|
||||
};
|
||||
|
||||
const getOsName = async () => {
|
||||
let name = '';
|
||||
if (appService?.appPlatform === 'tauri') {
|
||||
@@ -93,7 +100,7 @@ export const KOSyncSettingsWindow: React.FC = () => {
|
||||
name = platform;
|
||||
}
|
||||
}
|
||||
setOsName(name ? name.charAt(0).toUpperCase() + name.slice(1) : '');
|
||||
setOsName(formatOsName(name));
|
||||
};
|
||||
getOsName();
|
||||
}, [appService]);
|
||||
@@ -283,7 +290,7 @@ export const KOSyncSettingsWindow: React.FC = () => {
|
||||
onChange={handleChecksumMethodChange}
|
||||
options={[
|
||||
{ value: 'binary', label: _('File Content (recommended)') },
|
||||
{ value: 'filename', label: _('File Name') },
|
||||
{ value: 'filename', label: _('File Name'), disabled: true },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -334,6 +341,7 @@ export const KOSyncSettingsWindow: React.FC = () => {
|
||||
type='text'
|
||||
placeholder='https://koreader.sync.server'
|
||||
className='input input-bordered h-12 w-full focus:outline-none focus:ring-0'
|
||||
spellCheck='false'
|
||||
value={url}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
/>
|
||||
@@ -346,6 +354,7 @@ export const KOSyncSettingsWindow: React.FC = () => {
|
||||
type='text'
|
||||
placeholder={_('Your Username')}
|
||||
className='input input-bordered h-12 w-full focus:outline-none focus:ring-0'
|
||||
spellCheck='false'
|
||||
value={username}
|
||||
onChange={(e) => setUsername(e.target.value)}
|
||||
/>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import { md5 } from 'js-md5';
|
||||
import { Book } from '@/types/book';
|
||||
import { KoreaderSyncChecksumMethod } from '@/types/settings';
|
||||
import { getAPIBaseUrl } from '../environment';
|
||||
import { fetch as tauriFetch } from '@tauri-apps/plugin-http';
|
||||
import { KoSyncProxyPayload } from '@/types/kosync';
|
||||
import { isLanAddress } from '@/utils/network';
|
||||
import { getAPIBaseUrl, isTauriAppPlatform } from '../environment';
|
||||
|
||||
/**
|
||||
* Interface for KOSync progress response from the server
|
||||
@@ -23,6 +25,7 @@ export class KOSyncClient {
|
||||
private checksumMethod: KoreaderSyncChecksumMethod;
|
||||
private deviceId: string;
|
||||
private deviceName: string;
|
||||
private isLanServer: boolean;
|
||||
|
||||
constructor(
|
||||
serverUrl: string,
|
||||
@@ -38,6 +41,7 @@ export class KOSyncClient {
|
||||
this.checksumMethod = checksumMethod;
|
||||
this.deviceId = deviceId;
|
||||
this.deviceName = deviceName;
|
||||
this.isLanServer = isLanAddress(this.serverUrl);
|
||||
}
|
||||
|
||||
private async request(
|
||||
@@ -57,6 +61,24 @@ export class KOSyncClient {
|
||||
headers.set('X-Auth-Key', this.userkey);
|
||||
}
|
||||
|
||||
if (this.isLanServer) {
|
||||
const fetch = isTauriAppPlatform() ? tauriFetch : window.fetch;
|
||||
const directUrl = `${this.serverUrl}${endpoint}`;
|
||||
|
||||
return fetch(directUrl, {
|
||||
method,
|
||||
headers: {
|
||||
accept: 'application/vnd.koreader.v1+json',
|
||||
...Object.fromEntries(headers.entries()),
|
||||
},
|
||||
body,
|
||||
danger: {
|
||||
acceptInvalidCerts: true,
|
||||
acceptInvalidHostnames: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const proxyUrl = `${getAPIBaseUrl()}/kosync`;
|
||||
|
||||
const proxyBody: KoSyncProxyPayload = {
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
export const isLanAddress = (url: string) => {
|
||||
try {
|
||||
const urlObj = new URL(url);
|
||||
const hostname = urlObj.hostname;
|
||||
|
||||
if (hostname === 'localhost' || hostname === '127.0.0.1') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check for IPv4 private ranges
|
||||
const ipv4Regex = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
||||
const match = hostname.match(ipv4Regex);
|
||||
|
||||
if (match) {
|
||||
const [, a, b, c, d] = match.map(Number);
|
||||
if (a === undefined || b === undefined || c === undefined || d === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate IP format
|
||||
if (a > 255 || b > 255 || c > 255 || d > 255) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check private IP ranges:
|
||||
// 10.0.0.0/8 (10.0.0.0 to 10.255.255.255)
|
||||
if (a === 10) return true;
|
||||
|
||||
// 172.16.0.0/12 (172.16.0.0 to 172.31.255.255)
|
||||
if (a === 172 && b >= 16 && b <= 31) return true;
|
||||
|
||||
// 192.168.0.0/16 (192.168.0.0 to 192.168.255.255)
|
||||
if (a === 192 && b === 168) return true;
|
||||
|
||||
// 169.254.0.0/16 (link-local addresses)
|
||||
if (a === 169 && b === 254) return true;
|
||||
}
|
||||
|
||||
// Check for IPv6 private addresses (simplified check)
|
||||
if (hostname.includes(':')) {
|
||||
if (
|
||||
hostname.startsWith('::1') ||
|
||||
hostname.startsWith('fe80:') ||
|
||||
hostname.startsWith('fc00:') ||
|
||||
hostname.startsWith('fd00:')
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user