Compare commits

..
20 Commits
Author SHA1 Message Date
fyears 3e7e05fc3d bump to 0.3.21
Release A New Version / build (16.x) (push) Failing after 40s
2022-04-30 16:01:24 +08:00
fyears 391df3ed2d adjust focus 2022-04-30 16:00:53 +08:00
fyears c542789c93 update sync 1 sec 2022-04-30 15:55:25 +08:00
fyears 48e5601a52 bump to 0.3.20
Release A New Version / build (16.x) (push) Failing after 37s
2022-04-30 15:45:23 +08:00
fyears 054a9a3c01 add more verbose hint about the json 2022-04-30 15:40:56 +08:00
fyears 66dcaf4e4c add debug log 2022-04-30 15:23:16 +08:00
fyears 6d29554033 force refresh req every time for s3 2022-04-30 15:22:52 +08:00
fyears 4ed0d735a2 update all packages to latest 2022-04-30 14:22:34 +08:00
fyears 26dff02daa format 2022-04-30 11:59:38 +08:00
fyears 1b1083d746 better esbuild 2022-04-30 11:59:18 +08:00
fyears 6db005018d Merge branch 'moritzlang-add-apache-example-conf' 2022-04-27 23:39:26 +08:00
fyears 8d25ddb636 Merge branch 'add-apache-example-conf' of https://github.com/moritzlang/remotely-save into moritzlang-add-apache-example-conf 2022-04-27 23:39:03 +08:00
fyears b0d41478a3 Merge branch 'n0k0m3-master' 2022-04-27 23:32:27 +08:00
fyears f69adf273a add special hints 2022-04-27 23:32:15 +08:00
n0k0m3 4b4a9b0989 Add CORS header guide for Nextcloud/Owncloud 2022-04-18 11:22:23 -04:00
fyears bfe11f44dc make more s3 req to lower 2022-04-18 21:30:02 +08:00
fyears d25303cfac update s3 pack 2022-04-18 21:29:38 +08:00
fyears ebd62b1581 new s3 every request to avoid request expired 2022-04-18 00:56:25 +08:00
fyears 13537d1481 insert dry run into plan records 2022-04-18 00:22:00 +08:00
Moritz 2eda5618df Add apache example configuration 2022-02-20 22:54:30 +01:00
16 changed files with 160 additions and 76 deletions
+2
View File
@@ -92,6 +92,8 @@ Additionally, the plugin author may occasionally visit Obsidian official forum a
- If you are using Obsidian desktop < 0.13.25 or iOS < 1.1.1 or any Android version: - If you are using Obsidian desktop < 0.13.25 or iOS < 1.1.1 or any Android version:
- The webdav server has to be enabled CORS for requests from `app://obsidian.md` and `capacitor://localhost` and `http://localhost`, **AND** all webdav HTTP methods, **AND** all webdav headers. These are required, because Obsidian mobile works like a browser and mobile plugins are limited by CORS policies unless under a upgraded Obsidian version. - The webdav server has to be enabled CORS for requests from `app://obsidian.md` and `capacitor://localhost` and `http://localhost`, **AND** all webdav HTTP methods, **AND** all webdav headers. These are required, because Obsidian mobile works like a browser and mobile plugins are limited by CORS policies unless under a upgraded Obsidian version.
- Popular software NextCloud, OwnCloud, `rclone serve webdav` do **NOT** enable CORS by default. If you are using any of them, you should evaluate the risk, and find a way to enable CORS, before using this plugin, or use a upgraded Obsidian version. - Popular software NextCloud, OwnCloud, `rclone serve webdav` do **NOT** enable CORS by default. If you are using any of them, you should evaluate the risk, and find a way to enable CORS, before using this plugin, or use a upgraded Obsidian version.
- **Unofficial** workaround: NextCloud users can **evaluate the risk by themselves**, and if decide to accept the risk, they can install [WebAppPassword](https://apps.nextcloud.com/apps/webapppassword) app, and add `app://obsidian.md`, `capacitor://localhost`, `http://localhost` to `Allowed origins`
- **Unofficial** workaround: OwnCloud users can **evaluate the risk by themselves**, and if decide to accept the risk, they can download `.tar.gz` of `WebAppPassword` above and manually install and configure it on their instances.
- The plugin is tested successfully under python package [`wsgidav` (version 4.0)](https://github.com/mar10/wsgidav). See [this issue](https://github.com/mar10/wsgidav/issues/239) for some details. - The plugin is tested successfully under python package [`wsgidav` (version 4.0)](https://github.com/mar10/wsgidav). See [this issue](https://github.com/mar10/wsgidav/issues/239) for some details.
- Your data would be synced to a `${vaultName}` sub folder on your webdav server. - Your data would be synced to a `${vaultName}` sub folder on your webdav server.
- Password-based end-to-end encryption is also supported. But please be aware that **the vault name itself is not encrypted**. - Password-based end-to-end encryption is also supported. But please be aware that **the vault name itself is not encrypted**.
+25
View File
@@ -0,0 +1,25 @@
# How To Configure Apache CORS Rules for Webdav
This method is [contributed by community](https://github.com/remotely-save/remotely-save/pull/31).
You should evaluate the risk by yourself before trying this method.
**You are strongly advised to backup your original Apache configuration files before making any changes.**
```apacheconf
<IfModule mod_headers.c>
# Obsidian webdav
SetEnvIf Origin "^app://obsidian.md$" IS_OBSIDIAN
SetEnvIf Origin "^capacitor://localhost$" IS_OBSIDIAN
SetEnvIf Origin "^http://localhost$" IS_OBSIDIAN
Header always set Access-Control-Allow-Origin "*" env=IS_OBSIDIAN
Header always set Access-Control-Allow-Methods "GET, HEAD, POST, PUT, OPTIONS, MOVE, DELETE, COPY, LOCK, UNLOCK, PROPFIND" env=IS_OBSIDIAN
Header always set Access-Control-Allow-Headers "Authorization, Depth, DNT, User-Agent, Keep-Alive, Content-Type, accept, origin, X-Requested-With" env=IS_OBSIDIAN
Header always set Access-Control-Expose-Headers "etag, dav" env=IS_OBSIDIAN
# Allow OPTION request without authentication and respond with status 200
RewriteCond %{ENV:IS_OBSIDIAN} 1
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
</IfModule>
```
+7 -2
View File
@@ -4,6 +4,11 @@ The plugin is developed for the browser environment. The "fake" browser behind t
[MDN has a doc about CORS.](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) [MDN has a doc about CORS.](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
From Obsidian desktop >= 0.13.25 or mobile >= 1.1.1, Obsidian [provides a new API `requiestUrl`](https://forum.obsidian.md/t/obsidian-release-v0-13-25-insider-build/32701), that allows the plugin to fully bypass the CORS issue. As of Mar 2022, the latest public-released Obsidian desktop has supported this API, but the Obsidian mobile still stays in insider. 1. From Obsidian desktop >= 0.13.25 or mobile >= 1.1.1, Obsidian [provides a new API `requiestUrl`](https://forum.obsidian.md/t/obsidian-release-v0-13-25-insider-build/32701), that allows the plugin to fully bypass the CORS issue. As of Mar 2022, the latest public-released Obsidian desktop has supported this API, but the Obsidian mobile still stays in insider.
For using this plugin in Obsidian desktop < 0.13.25 or mobile < 1.1.1, we need to configure the server side to return the header `Access-Control-Allow-Origin` allowing the origins `app://obsidian.md` and `capacitor://localhost` and `http://localhost`. Here is an example [configuration for Amazon S3](./s3_cors_configure.md). 2. For using this plugin in Obsidian desktop < 0.13.25 or mobile < 1.1.1, we need to configure the server side to return the header `Access-Control-Allow-Origin` allowing the origins `app://obsidian.md` and `capacitor://localhost` and `http://localhost`.
Example configurations:
- [Amazon S3](./s3_cors_configure.md)
- [Apache](./apache_cors_configure.md) ([contributed by community](https://github.com/remotely-save/remotely-save/pull/31))
+4 -1
View File
@@ -31,11 +31,11 @@ esbuild
"obsidian", "obsidian",
"electron", "electron",
"fs", "fs",
"crypto",
"tls", "tls",
"net", "net",
// ...builtins // ...builtins
], ],
inject: ["./esbuild.injecthelper.mjs"],
format: "cjs", format: "cjs",
watch: !prod, watch: !prod,
target: "es2016", target: "es2016",
@@ -48,6 +48,9 @@ esbuild
"process.env.DEFAULT_DROPBOX_APP_KEY": `"${DEFAULT_DROPBOX_APP_KEY}"`, "process.env.DEFAULT_DROPBOX_APP_KEY": `"${DEFAULT_DROPBOX_APP_KEY}"`,
"process.env.DEFAULT_ONEDRIVE_CLIENT_ID": `"${DEFAULT_ONEDRIVE_CLIENT_ID}"`, "process.env.DEFAULT_ONEDRIVE_CLIENT_ID": `"${DEFAULT_ONEDRIVE_CLIENT_ID}"`,
"process.env.DEFAULT_ONEDRIVE_AUTHORITY": `"${DEFAULT_ONEDRIVE_AUTHORITY}"`, "process.env.DEFAULT_ONEDRIVE_AUTHORITY": `"${DEFAULT_ONEDRIVE_AUTHORITY}"`,
global: "window",
"process.env.NODE_DEBUG": `undefined`, // ugly fix
"process.env.DEBUG": `undefined`, // ugly fix
}, },
}) })
.catch(() => process.exit(1)); .catch(() => process.exit(1));
+2
View File
@@ -0,0 +1,2 @@
export let Buffer = require("buffer").Buffer;
export let process = require("process/browser");
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"id": "remotely-save", "id": "remotely-save",
"name": "Remotely Save", "name": "Remotely Save",
"version": "0.3.19", "version": "0.3.21",
"minAppVersion": "0.13.21", "minAppVersion": "0.13.21",
"description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.", "description": "Yet another unofficial plugin allowing users to synchronize notes between local device and the cloud service.",
"author": "fyears", "author": "fyears",
+39 -39
View File
@@ -1,6 +1,6 @@
{ {
"name": "remotely-save", "name": "remotely-save",
"version": "0.3.19", "version": "0.3.21",
"description": "This is yet another sync plugin for Obsidian app.", "description": "This is yet another sync plugin for Obsidian app.",
"scripts": { "scripts": {
"dev2": "node esbuild.config.mjs", "dev2": "node esbuild.config.mjs",
@@ -23,73 +23,73 @@
"author": "", "author": "",
"license": "Apache-2.0", "license": "Apache-2.0",
"devDependencies": { "devDependencies": {
"@microsoft/microsoft-graph-types": "^2.11.0", "@microsoft/microsoft-graph-types": "^2.19.0",
"@types/chai": "^4.2.22", "@types/chai": "^4.3.1",
"@types/chai-as-promised": "^7.1.4", "@types/chai-as-promised": "^7.1.5",
"@types/jsdom": "^16.2.13", "@types/jsdom": "^16.2.14",
"@types/lodash": "^4.14.178", "@types/lodash": "^4.14.182",
"@types/mime-types": "^2.1.1", "@types/mime-types": "^2.1.1",
"@types/mocha": "^9.0.0", "@types/mocha": "^9.1.1",
"@types/mustache": "^4.1.2", "@types/mustache": "^4.1.2",
"@types/node": "^14.14.37", "@types/node": "^17.0.30",
"@types/qrcode": "^1.4.1", "@types/qrcode": "^1.4.2",
"builtin-modules": "^3.2.0", "builtin-modules": "^3.2.0",
"chai": "^4.3.4", "chai": "^4.3.6",
"chai-as-promised": "^7.1.1", "chai-as-promised": "^7.1.1",
"cross-env": "^7.0.3", "cross-env": "^7.0.3",
"dotenv": "^10.0.0", "dotenv": "^16.0.0",
"esbuild": "^0.14.27", "esbuild": "^0.14.38",
"jsdom": "^19.0.0", "jsdom": "^19.0.0",
"mocha": "^9.1.3", "mocha": "^9.2.2",
"prettier": "^2.4.1", "prettier": "^2.6.2",
"ts-loader": "^9.2.6", "ts-loader": "^9.2.9",
"ts-node": "^10.4.0", "ts-node": "^10.7.0",
"tslib": "^2.2.0", "tslib": "^2.4.0",
"typescript": "^4.4.4", "typescript": "^4.6.4",
"webdav-server": "^2.6.2", "webdav-server": "^2.6.2",
"webpack": "^5.64.4", "webpack": "^5.72.0",
"webpack-cli": "^4.9.1" "webpack-cli": "^4.9.2"
}, },
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.67.0", "@aws-sdk/client-s3": "^3.81.0",
"@aws-sdk/fetch-http-handler": "^3.58.0", "@aws-sdk/fetch-http-handler": "^3.78.0",
"@aws-sdk/lib-storage": "^3.67.0", "@aws-sdk/lib-storage": "^3.81.0",
"@aws-sdk/protocol-http": "^3.58.0", "@aws-sdk/protocol-http": "^3.78.0",
"@aws-sdk/querystring-builder": "^3.55.0", "@aws-sdk/querystring-builder": "^3.78.0",
"@aws-sdk/signature-v4-crt": "^3.66.0", "@aws-sdk/signature-v4-crt": "^3.78.0",
"@aws-sdk/types": "^3.55.0", "@aws-sdk/types": "^3.78.0",
"@azure/msal-node": "^1.6.0", "@azure/msal-node": "^1.8.0",
"@fyears/tsqueue": "^1.0.1", "@fyears/tsqueue": "^1.0.1",
"@microsoft/microsoft-graph-client": "^3.0.1", "@microsoft/microsoft-graph-client": "^3.0.2",
"acorn": "^8.5.0", "acorn": "^8.7.1",
"aggregate-error": "^4.0.0", "aggregate-error": "^4.0.0",
"assert": "^2.0.0", "assert": "^2.0.0",
"aws-crt": "^1.10.1", "aws-crt": "^1.12.1",
"buffer": "^6.0.3", "buffer": "^6.0.3",
"crypto-browserify": "^3.12.0", "crypto-browserify": "^3.12.0",
"delay": "^5.0.0", "delay": "^5.0.0",
"dropbox": "^10.22.0", "dropbox": "^10.28.0",
"emoji-regex": "^10.1.0", "emoji-regex": "^10.1.0",
"http-status-codes": "^2.2.0", "http-status-codes": "^2.2.0",
"localforage": "^1.10.0", "localforage": "^1.10.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"loglevel": "^1.8.0", "loglevel": "^1.8.0",
"lucide": "^0.17.12", "lucide": "^0.35.0",
"mime-types": "^2.1.33", "mime-types": "^2.1.35",
"mustache": "^4.2.0", "mustache": "^4.2.0",
"nanoid": "^3.1.30", "nanoid": "^3.3.3",
"obsidian": "^0.13.26", "obsidian": "^0.14.6",
"p-queue": "^7.2.0", "p-queue": "^7.2.0",
"path-browserify": "^1.0.1", "path-browserify": "^1.0.1",
"process": "^0.11.10", "process": "^0.11.10",
"qrcode": "^1.5.0", "qrcode": "^1.5.0",
"rfc4648": "^1.5.0", "rfc4648": "^1.5.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"stream-browserify": "^3.0.0", "stream-browserify": "^3.0.0",
"url": "^0.11.0", "url": "^0.11.0",
"util": "^0.12.4", "util": "^0.12.4",
"webdav": "^4.7.0", "webdav": "^4.9.0",
"webdav-fs": "^4.0.0", "webdav-fs": "^4.0.1",
"xregexp": "^5.1.0" "xregexp": "^5.1.0"
} }
} }
+2
View File
@@ -165,3 +165,5 @@ export const DEFAULT_DEBUG_FOLDER = "_debug_remotely_save/";
export const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX = export const DEFAULT_SYNC_PLANS_HISTORY_FILE_PREFIX =
"sync_plans_hist_exported_on_"; "sync_plans_hist_exported_on_";
export const DEFAULT_LOG_HISTORY_FILE_PREFIX = "log_hist_exported_on_"; export const DEFAULT_LOG_HISTORY_FILE_PREFIX = "log_hist_exported_on_";
export type SyncTriggerSourceType = "manual" | "auto" | "dry" | "autoOnceInit";
+6 -6
View File
@@ -9,7 +9,10 @@ import {
} from "obsidian"; } from "obsidian";
import cloneDeep from "lodash/cloneDeep"; import cloneDeep from "lodash/cloneDeep";
import { createElement, RotateCcw, RefreshCcw, FileText } from "lucide"; import { createElement, RotateCcw, RefreshCcw, FileText } from "lucide";
import type { RemotelySavePluginSettings } from "./baseTypes"; import type {
RemotelySavePluginSettings,
SyncTriggerSourceType,
} from "./baseTypes";
import { import {
COMMAND_CALLBACK, COMMAND_CALLBACK,
COMMAND_CALLBACK_ONEDRIVE, COMMAND_CALLBACK_ONEDRIVE,
@@ -89,8 +92,6 @@ interface OAuth2Info {
revokeAuthSetting?: Setting; revokeAuthSetting?: Setting;
} }
type SyncTriggerSourceType = "manual" | "auto" | "dry" | "autoOnceInit";
const iconNameSyncWait = `remotely-save-sync-wait`; const iconNameSyncWait = `remotely-save-sync-wait`;
const iconNameSyncRunning = `remotely-save-sync-running`; const iconNameSyncRunning = `remotely-save-sync-running`;
const iconNameLogs = `remotely-save-logs`; const iconNameLogs = `remotely-save-logs`;
@@ -286,6 +287,7 @@ export default class RemotelySavePlugin extends Plugin {
origMetadataOnRemote.deletions, origMetadataOnRemote.deletions,
localHistory, localHistory,
client.serviceType, client.serviceType,
triggerSource,
this.app.vault, this.app.vault,
this.settings.syncConfigDir, this.settings.syncConfigDir,
this.app.vault.configDir, this.app.vault.configDir,
@@ -293,9 +295,7 @@ export default class RemotelySavePlugin extends Plugin {
this.settings.password this.settings.password
); );
log.info(plan.mixedStates); // for debugging log.info(plan.mixedStates); // for debugging
if (triggerSource !== "dry") { await insertSyncPlanRecordByVault(this.db, plan, this.vaultRandomID);
await insertSyncPlanRecordByVault(this.db, plan, this.vaultRandomID);
}
// The operations above are almost read only and kind of safe. // The operations above are almost read only and kind of safe.
// The operations below begins to write or delete (!!!) something. // The operations below begins to write or delete (!!!) something.
+34 -8
View File
@@ -1,6 +1,7 @@
import isEqual from "lodash/isEqual"; import isEqual from "lodash/isEqual";
import { base64url } from "rfc4648"; import { base64url } from "rfc4648";
import { reverseString } from "./misc"; import { reverseString } from "./misc";
import { log } from "./moreOnLog";
const DEFAULT_README_FOR_METADATAONREMOTE = const DEFAULT_README_FOR_METADATAONREMOTE =
"Do NOT edit or delete the file manually. This file is for the plugin remotely-save to store some necessary meta data on the remote services. Its content is slightly obfuscated."; "Do NOT edit or delete the file manually. This file is for the plugin remotely-save to store some necessary meta data on the remote services. Its content is slightly obfuscated.";
@@ -69,19 +70,44 @@ export const deserializeMetadataOnRemote = (x: string | ArrayBuffer) => {
} else { } else {
y1 = new TextDecoder().decode(x); y1 = new TextDecoder().decode(x);
} }
const y2: any = JSON.parse(y1);
if (!("readme" in y2 && "d" in y2)) { let y2: any;
throw Error("invalid remote meta data file!"); try {
y2 = JSON.parse(y1);
} catch (e) {
throw new Error(
`invalid remote meta data file with first few chars: ${y1.slice(0, 5)}`
);
} }
const y3 = JSON.parse( if (!("readme" in y2 && "d" in y2)) {
( throw new Error(
'invalid remote meta data file (no "readme" or "d" fields)!'
);
}
let y3: string;
try {
y3 = (
base64url.parse(reverseString(y2["d"]), { base64url.parse(reverseString(y2["d"]), {
out: Buffer.allocUnsafe as any, out: Buffer.allocUnsafe as any,
loose: true, loose: true,
}) as Buffer }) as Buffer
).toString("utf-8") ).toString("utf-8");
) as MetadataOnRemote; } catch (e) {
return y3; throw new Error('invalid remote meta data file (invalid "d" field)!');
}
let y4: MetadataOnRemote;
try {
y4 = JSON.parse(y3) as MetadataOnRemote;
} catch (e) {
throw new Error(
`invalid remote meta data file with \"d\" field with first few chars: ${y3.slice(
0,
5
)}`
);
}
return y4;
}; };
+10 -8
View File
@@ -15,7 +15,6 @@ import { log } from "./moreOnLog";
export class RemoteClient { export class RemoteClient {
readonly serviceType: SUPPORTED_SERVICES_TYPE; readonly serviceType: SUPPORTED_SERVICES_TYPE;
readonly s3Client?: s3.S3Client;
readonly s3Config?: S3Config; readonly s3Config?: S3Config;
readonly webdavClient?: webdav.WrappedWebdavClient; readonly webdavClient?: webdav.WrappedWebdavClient;
readonly webdavConfig?: WebdavConfig; readonly webdavConfig?: WebdavConfig;
@@ -38,7 +37,6 @@ export class RemoteClient {
// so we use a ref not copy of config here // so we use a ref not copy of config here
if (serviceType === "s3") { if (serviceType === "s3") {
this.s3Config = s3Config; this.s3Config = s3Config;
this.s3Client = s3.getS3Client(this.s3Config);
} else if (serviceType === "webdav") { } else if (serviceType === "webdav") {
if (vaultName === undefined || saveUpdatedConfigFunc === undefined) { if (vaultName === undefined || saveUpdatedConfigFunc === undefined) {
throw Error( throw Error(
@@ -86,7 +84,7 @@ export class RemoteClient {
getRemoteMeta = async (fileOrFolderPath: string) => { getRemoteMeta = async (fileOrFolderPath: string) => {
if (this.serviceType === "s3") { if (this.serviceType === "s3") {
return await s3.getRemoteMeta( return await s3.getRemoteMeta(
this.s3Client, s3.getS3Client(this.s3Config),
this.s3Config, this.s3Config,
fileOrFolderPath fileOrFolderPath
); );
@@ -116,7 +114,7 @@ export class RemoteClient {
) => { ) => {
if (this.serviceType === "s3") { if (this.serviceType === "s3") {
return await s3.uploadToRemote( return await s3.uploadToRemote(
this.s3Client, s3.getS3Client(this.s3Config),
this.s3Config, this.s3Config,
fileOrFolderPath, fileOrFolderPath,
vault, vault,
@@ -168,7 +166,11 @@ export class RemoteClient {
listFromRemote = async (prefix?: string) => { listFromRemote = async (prefix?: string) => {
if (this.serviceType === "s3") { if (this.serviceType === "s3") {
return await s3.listFromRemote(this.s3Client, this.s3Config, prefix); return await s3.listFromRemote(
s3.getS3Client(this.s3Config),
this.s3Config,
prefix
);
} else if (this.serviceType === "webdav") { } else if (this.serviceType === "webdav") {
return await webdav.listFromRemote(this.webdavClient, prefix); return await webdav.listFromRemote(this.webdavClient, prefix);
} else if (this.serviceType === "dropbox") { } else if (this.serviceType === "dropbox") {
@@ -190,7 +192,7 @@ export class RemoteClient {
) => { ) => {
if (this.serviceType === "s3") { if (this.serviceType === "s3") {
return await s3.downloadFromRemote( return await s3.downloadFromRemote(
this.s3Client, s3.getS3Client(this.s3Config),
this.s3Config, this.s3Config,
fileOrFolderPath, fileOrFolderPath,
vault, vault,
@@ -241,7 +243,7 @@ export class RemoteClient {
) => { ) => {
if (this.serviceType === "s3") { if (this.serviceType === "s3") {
return await s3.deleteFromRemote( return await s3.deleteFromRemote(
this.s3Client, s3.getS3Client(this.s3Config),
this.s3Config, this.s3Config,
fileOrFolderPath, fileOrFolderPath,
password, password,
@@ -276,7 +278,7 @@ export class RemoteClient {
checkConnectivity = async (callbackFunc?: any) => { checkConnectivity = async (callbackFunc?: any) => {
if (this.serviceType === "s3") { if (this.serviceType === "s3") {
return await s3.checkConnectivity( return await s3.checkConnectivity(
this.s3Client, s3.getS3Client(this.s3Config),
this.s3Config, this.s3Config,
callbackFunc callbackFunc
); );
+13 -5
View File
@@ -83,17 +83,25 @@ class ObsHttpHandler extends FetchHttpHandler {
const body = const body =
method === "GET" || method === "HEAD" ? undefined : request.body; method === "GET" || method === "HEAD" ? undefined : request.body;
const transformedHeaders = { ...request.headers }; const transformedHeaders: Record<string, string> = {};
delete transformedHeaders["host"]; for (const key of Object.keys(request.headers)) {
delete transformedHeaders["Host"]; const keyLower = key.toLowerCase();
delete transformedHeaders["content-length"]; if (keyLower === "host" || keyLower === "content-length") {
delete transformedHeaders["Content-Length"]; continue;
}
transformedHeaders[keyLower] = request.headers[key];
}
let contentType: string = undefined; let contentType: string = undefined;
if (transformedHeaders["content-type"] !== undefined) { if (transformedHeaders["content-type"] !== undefined) {
contentType = transformedHeaders["content-type"]; contentType = transformedHeaders["content-type"];
} }
if (transformedHeaders["cache-control"] === undefined) {
// every time is a new request
transformedHeaders["cache-control"] = "no-cache";
}
let transformedBody: any = body; let transformedBody: any = body;
if (ArrayBuffer.isView(body)) { if (ArrayBuffer.isView(body)) {
transformedBody = bufferToArrayBuffer(body); transformedBody = bufferToArrayBuffer(body);
+6 -1
View File
@@ -645,8 +645,9 @@ const wrapTextWithPasswordHide = (text: TextComponent) => {
hider.innerHTML = eyeOff; hider.innerHTML = eyeOff;
hider.addEventListener("click", (e) => { hider.addEventListener("click", (e) => {
const isText = text.inputEl.getAttribute("type") === "text"; const isText = text.inputEl.getAttribute("type") === "text";
text.inputEl.setAttribute("type", isText ? "password" : "text");
hider.innerHTML = isText ? eyeOff : eye; hider.innerHTML = isText ? eyeOff : eye;
text.inputEl.setAttribute("type", isText ? "password" : "text");
text.inputEl.focus();
}); });
// the init type of text el is password // the init type of text el is password
@@ -745,6 +746,10 @@ export class RemotelySaveSettingTab extends PluginSettingTab {
.setDesc(t("settings_runoncestartup_desc")) .setDesc(t("settings_runoncestartup_desc"))
.addDropdown((dropdown) => { .addDropdown((dropdown) => {
dropdown.addOption("-1", t("settings_runoncestartup_notset")); dropdown.addOption("-1", t("settings_runoncestartup_notset"));
dropdown.addOption(
`${1000 * 1 * 1}`,
t("settings_runoncestartup_1sec")
);
dropdown.addOption( dropdown.addOption(
`${1000 * 10 * 1}`, `${1000 * 10 * 1}`,
t("settings_runoncestartup_10sec") t("settings_runoncestartup_10sec")
+7 -3
View File
@@ -7,13 +7,14 @@ import {
} from "obsidian"; } from "obsidian";
import AggregateError from "aggregate-error"; import AggregateError from "aggregate-error";
import PQueue from "p-queue"; import PQueue from "p-queue";
import { import type {
RemoteItem, RemoteItem,
SUPPORTED_SERVICES_TYPE, SyncTriggerSourceType,
DecisionType, DecisionType,
FileOrFolderMixedState, FileOrFolderMixedState,
API_VER_STAT_FOLDER, SUPPORTED_SERVICES_TYPE,
} from "./baseTypes"; } from "./baseTypes";
import { API_VER_STAT_FOLDER } from "./baseTypes";
import { import {
decryptBase32ToString, decryptBase32ToString,
decryptBase64urlToString, decryptBase64urlToString,
@@ -65,6 +66,7 @@ export type SyncStatusType =
export interface SyncPlanType { export interface SyncPlanType {
ts: number; ts: number;
tsFmt?: string; tsFmt?: string;
syncTriggerSource?: SyncTriggerSourceType;
remoteType: SUPPORTED_SERVICES_TYPE; remoteType: SUPPORTED_SERVICES_TYPE;
mixedStates: Record<string, FileOrFolderMixedState>; mixedStates: Record<string, FileOrFolderMixedState>;
} }
@@ -752,6 +754,7 @@ export const getSyncPlan = async (
remoteDeleteHistory: DeletionOnRemote[], remoteDeleteHistory: DeletionOnRemote[],
localFileHistory: FileFolderHistoryRecord[], localFileHistory: FileFolderHistoryRecord[],
remoteType: SUPPORTED_SERVICES_TYPE, remoteType: SUPPORTED_SERVICES_TYPE,
triggerSource: SyncTriggerSourceType,
vault: Vault, vault: Vault,
syncConfigDir: boolean, syncConfigDir: boolean,
configDir: string, configDir: string,
@@ -824,6 +827,7 @@ export const getSyncPlan = async (
ts: currTs, ts: currTs,
tsFmt: currTsFmt, tsFmt: currTsFmt,
remoteType: remoteType, remoteType: remoteType,
syncTriggerSource: triggerSource,
mixedStates: mixedStates, mixedStates: mixedStates,
} as SyncPlanType; } as SyncPlanType;
return { return {
+1 -1
View File
@@ -1,4 +1,4 @@
{ {
"0.3.2": "0.12.15", "0.3.2": "0.12.15",
"0.3.19": "0.13.21" "0.3.21": "0.13.21"
} }