Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a13f4566c | ||
|
|
d355f72b7a | ||
|
|
9b1eebdf90 | ||
|
|
2ce461ed6a | ||
|
|
3aa91a2a1e | ||
|
|
2a3e0524c5 | ||
|
|
2f20ca61ce | ||
|
|
68ec8b5454 | ||
|
|
2bbbd569c5 | ||
|
|
62936c4473 |
@@ -13,6 +13,8 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
environment: env-for-buildci
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
node-version: [16.x]
|
||||
|
||||
@@ -4,7 +4,7 @@ This is yet another unofficial sync plugin for Obsidian.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
- **This is NOT the [official sync service](https://github.com/fyears/obsidian-remotely-save.git) provided by Obsidian.**
|
||||
- **This is NOT the [official sync service](https://obsidian.md/sync) provided by Obsidian.**
|
||||
|
||||
## !!!Caution!!!
|
||||
|
||||
@@ -29,7 +29,7 @@ As of November 2021, the plugin is considered in BETA stage. **DO NOT USE IT for
|
||||
|
||||
## Download and Install
|
||||
|
||||
- Option #1: [](https://github.com/fyears/obsidian-remotely-save/actions/workflows/auto-build.yml) Every artifacts are placed in the "Summary" under every successful builds.
|
||||
- Option #1: [](https://github.com/fyears/remotely-save/actions/workflows/auto-build.yml) Every artifacts are placed in the "Summary" under every successful builds.
|
||||
- Option #2: Besides manually downloading the files, you can also use [Obsidian42 - BRAT](https://github.com/TfTHacker/obsidian42-brat) to install this plugin.
|
||||
- Option #3: The pluin would be submitted to the official "community plugin list" in near future.
|
||||
|
||||
@@ -49,7 +49,7 @@ As of November 2021, the plugin is considered in BETA stage. **DO NOT USE IT for
|
||||
|
||||
- **This plugin's function for Dropbox is not as mature as functions for S3.**
|
||||
- **This plugin is NOT an official Dropbox product.** The plugin just uses Dropbox's public API.
|
||||
- After the authorization, the plugin can read your name and email (which cannot be unselected on Dropbox api), and read and write files in your Dropbox's `/Apps/obsidian-remotely-save` folder.
|
||||
- After the authorization, the plugin can read your name and email (which cannot be unselected on Dropbox api), and read and write files in your Dropbox's `/Apps/remotely-save` folder.
|
||||
- If you decide to authorize this plugin to connect to Dropbox, please go to plugin's settings, and choose Dropbox then follow the instructions.
|
||||
- Password-based end-to-end encryption is also supported.
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ esbuild
|
||||
"obsidian",
|
||||
"electron",
|
||||
"fs",
|
||||
"crypto",
|
||||
// ...builtins
|
||||
],
|
||||
format: "cjs",
|
||||
|
||||
+3
-3
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"id": "obsidian-remotely-save",
|
||||
"id": "remotely-save",
|
||||
"name": "Remotely Save",
|
||||
"version": "0.1.10",
|
||||
"version": "0.2.1",
|
||||
"minAppVersion": "0.12.15",
|
||||
"description": "Yet another unofficial plugin allowing users to sync 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",
|
||||
"authorUrl": "https://github.com/fyears",
|
||||
"isDesktopOnly": false
|
||||
|
||||
+3
-6
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "obsidian-remotely-save",
|
||||
"version": "0.1.10",
|
||||
"name": "remotely-save",
|
||||
"version": "0.2.1",
|
||||
"description": "This is yet another sync plugin for Obsidian app.",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
@@ -13,10 +13,7 @@
|
||||
"browser": {
|
||||
"path": "path-browserify",
|
||||
"process": "process/browser",
|
||||
"stream": "stream-browserify",
|
||||
"crypto": "crypto-browserify",
|
||||
"util": "util/",
|
||||
"assert": "assert/"
|
||||
"stream": "stream-browserify"
|
||||
},
|
||||
"source": "main.ts",
|
||||
"keywords": [],
|
||||
|
||||
+14
-13
@@ -27,13 +27,16 @@ import type { InternalDBs } from "./localdb";
|
||||
import type { SyncStatusType, PasswordCheckType } from "./sync";
|
||||
import { isPasswordOk, getSyncPlan, doActualSync } from "./sync";
|
||||
|
||||
import { S3Config, DEFAULT_S3_CONFIG } from "./s3";
|
||||
import { WebdavConfig, DEFAULT_WEBDAV_CONFIG, WebdavAuthType } from "./webdav";
|
||||
import { S3Config, DEFAULT_S3_CONFIG } from "./remoteForS3";
|
||||
import {
|
||||
WebdavConfig,
|
||||
DEFAULT_WEBDAV_CONFIG,
|
||||
WebdavAuthType,
|
||||
} from "./remoteForWebdav";
|
||||
import {
|
||||
DropboxConfig,
|
||||
DEFAULT_DROPBOX_CONFIG,
|
||||
getCodeVerifierAndChallenge,
|
||||
getAuthUrl,
|
||||
getAuthUrlAndVerifier,
|
||||
sendAuthReq,
|
||||
setConfigBySuccessfullAuthInplace,
|
||||
} from "./remoteForDropbox";
|
||||
@@ -67,7 +70,7 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
syncStatus: SyncStatusType;
|
||||
|
||||
async onload() {
|
||||
console.log("loading plugin obsidian-remotely-save");
|
||||
console.log("loading plugin remotely-save");
|
||||
|
||||
await this.loadSettings();
|
||||
|
||||
@@ -191,7 +194,7 @@ export default class RemotelySavePlugin extends Plugin {
|
||||
}
|
||||
|
||||
onunload() {
|
||||
console.log("unloading plugin obsidian-remotely-save");
|
||||
console.log("unloading plugin remotely-save");
|
||||
this.destroyDBs();
|
||||
}
|
||||
|
||||
@@ -296,13 +299,11 @@ export class DropboxAuthModal extends Modal {
|
||||
this.revokeAuthSetting = revokeAuthSetting;
|
||||
}
|
||||
|
||||
onOpen() {
|
||||
async onOpen() {
|
||||
let { contentEl } = this;
|
||||
|
||||
const k = getCodeVerifierAndChallenge();
|
||||
const authUrl = getAuthUrl(
|
||||
this.plugin.settings.dropbox.clientID,
|
||||
k.challenge
|
||||
const { authUrl, verifier } = await getAuthUrlAndVerifier(
|
||||
this.plugin.settings.dropbox.clientID
|
||||
);
|
||||
|
||||
contentEl.createEl("p", {
|
||||
@@ -336,7 +337,7 @@ export class DropboxAuthModal extends Modal {
|
||||
try {
|
||||
const authRes = await sendAuthReq(
|
||||
this.plugin.settings.dropbox.clientID,
|
||||
k.verifier,
|
||||
verifier,
|
||||
authCode
|
||||
);
|
||||
const self = this;
|
||||
@@ -602,7 +603,7 @@ class RemotelySaveSettingTab extends PluginSettingTab {
|
||||
cls: "dropbox-disclaimer",
|
||||
});
|
||||
dropboxDiv.createEl("p", {
|
||||
text: "We will create a folder App/obsidian-remotely-save on your Dropbox. All files/folders sync would happen inside this folder.",
|
||||
text: "We will create a folder Apps/remotely-save on your Dropbox. All files/folders sync would happen inside this folder.",
|
||||
});
|
||||
|
||||
const dropboxSelectAuthDiv = dropboxDiv.createDiv();
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import { Vault } from "obsidian";
|
||||
|
||||
import type { SUPPORTED_SERVICES_TYPE } from "./baseTypes";
|
||||
import * as s3 from "./s3";
|
||||
import * as webdav from "./webdav";
|
||||
import * as s3 from "./remoteForS3";
|
||||
import * as webdav from "./remoteForWebdav";
|
||||
import * as dropbox from "./remoteForDropbox";
|
||||
|
||||
export class RemoteClient {
|
||||
|
||||
+41
-26
@@ -1,9 +1,7 @@
|
||||
import * as path from "path";
|
||||
import { FileStats, Vault } from "obsidian";
|
||||
import { Buffer } from "buffer";
|
||||
import * as crypto from "crypto";
|
||||
|
||||
import { Dropbox, DropboxResponse, files } from "dropbox";
|
||||
import { Dropbox, DropboxAuth, DropboxResponse, files } from "dropbox";
|
||||
export { Dropbox } from "dropbox";
|
||||
import { RemoteItem } from "./baseTypes";
|
||||
import {
|
||||
@@ -162,32 +160,28 @@ const fixLastModifiedTimeInplace = (allFilesFolders: RemoteItem[]) => {
|
||||
// see https://dropbox.tech/developers/pkce--what-and-why-
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const specialBase64Encode = (str: Buffer) => {
|
||||
return str
|
||||
.toString("base64")
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=/g, "");
|
||||
};
|
||||
const sha256 = (buffer: string) => {
|
||||
return crypto.createHash("sha256").update(buffer).digest();
|
||||
};
|
||||
|
||||
export const getCodeVerifierAndChallenge = () => {
|
||||
const codeVerifier = specialBase64Encode(crypto.randomBytes(32));
|
||||
// console.log(`Client generated code_verifier: ${codeVerifier}`);
|
||||
const codeChallenge = specialBase64Encode(sha256(codeVerifier));
|
||||
// console.log(`Client generated code_challenge: ${codeChallenge}`);
|
||||
export const getAuthUrlAndVerifier = async (appKey: string) => {
|
||||
const auth = new DropboxAuth({
|
||||
clientId: appKey,
|
||||
});
|
||||
const authUrl = (
|
||||
await auth.getAuthenticationUrl(
|
||||
undefined,
|
||||
undefined,
|
||||
"code",
|
||||
"offline",
|
||||
undefined,
|
||||
"none",
|
||||
true
|
||||
)
|
||||
).toString();
|
||||
const verifier = auth.getCodeVerifier();
|
||||
return {
|
||||
verifier: codeVerifier,
|
||||
challenge: codeChallenge,
|
||||
authUrl: authUrl,
|
||||
verifier: verifier,
|
||||
};
|
||||
};
|
||||
|
||||
export const getAuthUrl = (appKey: string, challenge: string) => {
|
||||
return `https://www.dropbox.com/oauth2/authorize?client_id=${appKey}&response_type=code&code_challenge=${challenge}&code_challenge_method=S256&token_access_type=offline`;
|
||||
};
|
||||
|
||||
export interface DropboxSuccessAuthRes {
|
||||
access_token: string;
|
||||
token_type: "bearer";
|
||||
@@ -487,20 +481,41 @@ export const listFromRemote = async (
|
||||
throw Error("prefix not supported (yet)");
|
||||
}
|
||||
await client.init();
|
||||
const res = await client.dropbox.filesListFolder({
|
||||
let res = await client.dropbox.filesListFolder({
|
||||
path: `/${client.vaultName}`,
|
||||
recursive: true,
|
||||
include_deleted: false,
|
||||
limit: 1000,
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
throw Error(JSON.stringify(res));
|
||||
}
|
||||
// console.log(res);
|
||||
|
||||
const contents = res.result.entries;
|
||||
const unifiedContents = contents
|
||||
.filter((x) => x[".tag"] !== "deleted")
|
||||
.filter((x) => x.path_display !== `/${client.vaultName}`)
|
||||
.map((x) => fromDropboxItemToRemoteItem(x, client.vaultName));
|
||||
|
||||
while (res.result.has_more) {
|
||||
res = await client.dropbox.filesListFolderContinue({
|
||||
cursor: res.result.cursor,
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
throw Error(JSON.stringify(res));
|
||||
}
|
||||
|
||||
const contents2 = res.result.entries;
|
||||
const unifiedContents2 = contents2
|
||||
.filter((x) => x[".tag"] !== "deleted")
|
||||
.filter((x) => x.path_display !== `/${client.vaultName}`)
|
||||
.map((x) => fromDropboxItemToRemoteItem(x, client.vaultName));
|
||||
unifiedContents.push(...unifiedContents2);
|
||||
}
|
||||
|
||||
fixLastModifiedTimeInplace(unifiedContents);
|
||||
|
||||
return {
|
||||
Contents: unifiedContents,
|
||||
};
|
||||
|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
{
|
||||
"0.1.10": "0.12.15"
|
||||
"0.2.1": "0.12.15"
|
||||
}
|
||||
|
||||
+2
-1
@@ -43,7 +43,8 @@ module.exports = {
|
||||
// buffer: require.resolve("buffer/"),
|
||||
// console: require.resolve("console-browserify"),
|
||||
// constants: require.resolve("constants-browserify"),
|
||||
crypto: require.resolve("crypto-browserify"),
|
||||
// crypto: require.resolve("crypto-browserify"),
|
||||
crypto: false,
|
||||
// domain: require.resolve("domain-browser"),
|
||||
// events: require.resolve("events"),
|
||||
// http: require.resolve("stream-http"),
|
||||
|
||||
Reference in New Issue
Block a user