mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-24 22:09:08 +08:00
fix(core): fix ios blob upload (#10263)
This commit is contained in:
@@ -8,8 +8,11 @@ import { router } from '@affine/core/mobile/router';
|
||||
import { configureCommonModules } from '@affine/core/modules';
|
||||
import { AIButtonProvider } from '@affine/core/modules/ai-button';
|
||||
import {
|
||||
AuthProvider,
|
||||
AuthService,
|
||||
DefaultServerService,
|
||||
ServerScope,
|
||||
ServerService,
|
||||
ServersService,
|
||||
ValidatorProvider,
|
||||
} from '@affine/core/modules/cloud';
|
||||
@@ -51,9 +54,11 @@ import { RouterProvider } from 'react-router-dom';
|
||||
|
||||
import { BlocksuiteMenuConfigProvider } from './bs-menu-config';
|
||||
import { ModalConfigProvider } from './modal-config';
|
||||
import { Auth } from './plugins/auth';
|
||||
import { Hashcash } from './plugins/hashcash';
|
||||
import { Intelligents } from './plugins/intelligents';
|
||||
import { NbStoreNativeDBApis } from './plugins/nbstore';
|
||||
import { writeEndpointToken } from './proxy';
|
||||
import { enableNavigationGesture$ } from './web-navigation-control';
|
||||
|
||||
const storeManagerClient = createStoreManagerClient();
|
||||
@@ -134,6 +139,41 @@ framework.impl(AIButtonProvider, {
|
||||
return Intelligents.dismissIntelligentsButton();
|
||||
},
|
||||
});
|
||||
framework.scope(ServerScope).override(AuthProvider, resolver => {
|
||||
const serverService = resolver.get(ServerService);
|
||||
const endpoint = serverService.server.baseUrl;
|
||||
return {
|
||||
async signInMagicLink(email, linkToken) {
|
||||
const { token } = await Auth.signInMagicLink({
|
||||
endpoint,
|
||||
email,
|
||||
token: linkToken,
|
||||
});
|
||||
await writeEndpointToken(endpoint, token);
|
||||
},
|
||||
async signInOauth(code, state, _provider) {
|
||||
const { token } = await Auth.signInOauth({
|
||||
endpoint,
|
||||
code,
|
||||
state,
|
||||
});
|
||||
await writeEndpointToken(endpoint, token);
|
||||
return {};
|
||||
},
|
||||
async signInPassword(credential) {
|
||||
const { token } = await Auth.signInPassword({
|
||||
endpoint,
|
||||
...credential,
|
||||
});
|
||||
await writeEndpointToken(endpoint, token);
|
||||
},
|
||||
async signOut() {
|
||||
await Auth.signOut({
|
||||
endpoint,
|
||||
});
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const frameworkProvider = framework.provider();
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
export interface AuthPlugin {
|
||||
signInMagicLink(options: {
|
||||
endpoint: string;
|
||||
email: string;
|
||||
token: string;
|
||||
}): Promise<{ token: string }>;
|
||||
signInOauth(options: {
|
||||
endpoint: string;
|
||||
code: string;
|
||||
state: string;
|
||||
}): Promise<{ token: string }>;
|
||||
signInPassword(options: {
|
||||
endpoint: string;
|
||||
email: string;
|
||||
password: string;
|
||||
verifyToken?: string;
|
||||
challenge?: string;
|
||||
}): Promise<{ token: string }>;
|
||||
signOut(options: { endpoint: string }): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
import { registerPlugin } from '@capacitor/core';
|
||||
|
||||
import type { AuthPlugin } from './definitions';
|
||||
|
||||
const Auth = registerPlugin<AuthPlugin>('Auth');
|
||||
|
||||
export * from './definitions';
|
||||
export { Auth };
|
||||
@@ -0,0 +1,65 @@
|
||||
import { openDB } from 'idb';
|
||||
|
||||
/**
|
||||
* the below code includes the custom fetch and xmlhttprequest implementation for ios webview.
|
||||
* should be included in the entry file of the app or webworker.
|
||||
*/
|
||||
const rawFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
const request = new Request(input, init);
|
||||
|
||||
const origin = new URL(request.url, globalThis.location.origin).origin;
|
||||
|
||||
const token = await readEndpointToken(origin);
|
||||
if (token) {
|
||||
request.headers.set('Authorization', `Bearer ${token}`);
|
||||
}
|
||||
|
||||
return rawFetch(request);
|
||||
};
|
||||
|
||||
const rawXMLHttpRequest = globalThis.XMLHttpRequest;
|
||||
globalThis.XMLHttpRequest = class extends rawXMLHttpRequest {
|
||||
override send(body?: Document | XMLHttpRequestBodyInit | null): void {
|
||||
const origin = new URL(this.responseURL, globalThis.location.origin).origin;
|
||||
|
||||
readEndpointToken(origin).then(
|
||||
token => {
|
||||
if (token) {
|
||||
this.setRequestHeader('Authorization', `Bearer ${token}`);
|
||||
}
|
||||
return super.send(body);
|
||||
},
|
||||
() => {
|
||||
throw new Error('Failed to read token');
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export async function readEndpointToken(
|
||||
endpoint: string
|
||||
): Promise<string | null> {
|
||||
const idb = await openDB('affine-token', 1, {
|
||||
upgrade(db) {
|
||||
if (!db.objectStoreNames.contains('tokens')) {
|
||||
db.createObjectStore('tokens', { keyPath: 'endpoint' });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const token = await idb.get('tokens', endpoint);
|
||||
return token ? token.token : null;
|
||||
}
|
||||
|
||||
export async function writeEndpointToken(endpoint: string, token: string) {
|
||||
const db = await openDB('affine-token', 1, {
|
||||
upgrade(db) {
|
||||
if (!db.objectStoreNames.contains('tokens')) {
|
||||
db.createObjectStore('tokens', { keyPath: 'endpoint' });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
await db.put('tokens', { endpoint, token });
|
||||
}
|
||||
@@ -1,62 +1,2 @@
|
||||
import '@affine/core/bootstrap/browser';
|
||||
|
||||
/**
|
||||
* the below code includes the custom fetch and xmlhttprequest implementation for ios webview.
|
||||
* should be included in the entry file of the app or webworker.
|
||||
*/
|
||||
|
||||
/*
|
||||
* we override the browser's fetch function with our custom fetch function to
|
||||
* overcome the restrictions of cross-domain and third-party cookies in ios webview.
|
||||
*
|
||||
* the custom fetch function will convert the request to `affine-http://` or `affine-https://`
|
||||
* and send the request to the server.
|
||||
*/
|
||||
const rawFetch = globalThis.fetch;
|
||||
globalThis.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
|
||||
let url = new URL(
|
||||
typeof input === 'string'
|
||||
? input
|
||||
: input instanceof URL
|
||||
? input.toString()
|
||||
: input.url,
|
||||
globalThis.location.origin
|
||||
).href;
|
||||
|
||||
if (url.startsWith('capacitor:')) {
|
||||
return rawFetch(input, init);
|
||||
}
|
||||
|
||||
if (url.startsWith('http:')) {
|
||||
url = 'affine-http:' + url.slice(5);
|
||||
}
|
||||
|
||||
if (url.startsWith('https:')) {
|
||||
url = 'affine-https:' + url.slice(6);
|
||||
}
|
||||
|
||||
return rawFetch(url, input instanceof Request ? input : init);
|
||||
};
|
||||
|
||||
const rawXMLHttpRequest = globalThis.XMLHttpRequest;
|
||||
globalThis.XMLHttpRequest = class extends rawXMLHttpRequest {
|
||||
override open(
|
||||
method: string,
|
||||
url: string,
|
||||
async?: boolean,
|
||||
user?: string,
|
||||
password?: string
|
||||
) {
|
||||
let normalizedUrl = new URL(url, globalThis.location.origin).href;
|
||||
|
||||
if (normalizedUrl.startsWith('http:')) {
|
||||
url = 'affine-http:' + url.slice(5);
|
||||
}
|
||||
|
||||
if (normalizedUrl.startsWith('https:')) {
|
||||
url = 'affine-https:' + url.slice(6);
|
||||
}
|
||||
|
||||
(super.open as any)(method, url, async, user, password);
|
||||
}
|
||||
};
|
||||
import './proxy';
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import './setup';
|
||||
|
||||
import { broadcastChannelStorages } from '@affine/nbstore/broadcast-channel';
|
||||
import { cloudStorages } from '@affine/nbstore/cloud';
|
||||
import {
|
||||
cloudStorages,
|
||||
configureSocketAuthMethod,
|
||||
} from '@affine/nbstore/cloud';
|
||||
import {
|
||||
bindNativeDBApis,
|
||||
type NativeDBApis,
|
||||
@@ -14,6 +17,18 @@ import {
|
||||
import { type MessageCommunicapable, OpConsumer } from '@toeverything/infra/op';
|
||||
import { AsyncCall } from 'async-call-rpc';
|
||||
|
||||
import { readEndpointToken } from './proxy';
|
||||
|
||||
configureSocketAuthMethod((endpoint, cb) => {
|
||||
readEndpointToken(endpoint)
|
||||
.then(token => {
|
||||
cb({ token });
|
||||
})
|
||||
.catch(e => {
|
||||
console.error(e);
|
||||
});
|
||||
});
|
||||
|
||||
globalThis.addEventListener('message', e => {
|
||||
if (e.data.type === 'native-db-api-channel') {
|
||||
const port = e.ports[0] as MessagePort;
|
||||
|
||||
Reference in New Issue
Block a user