Skip to content

Commit

Permalink
Lowercases name of Remote.ts & eliminates local copies of Dropbox URLs
Browse files Browse the repository at this point in the history
  • Loading branch information
DougReeder committed Oct 22, 2022
1 parent 520e95a commit a688512
Show file tree
Hide file tree
Showing 9 changed files with 148 additions and 31 deletions.
2 changes: 1 addition & 1 deletion doc/getting-started/dropbox-and-google-drive.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ An app key can be obtained by `registering your app
* files.content.write
* You need to set one or more OAuth2 redirect URIs for all routes a user can
connect from, for example ``http://localhost:8000`` for an app you are
developing locally. If the path is '/', remoteStorage drops it.
developing locally. If the path is '/', rs.js drops it.

Known issues
^^^^^^^^^^^^
Expand Down
2 changes: 1 addition & 1 deletion src/authorize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import UnauthorizedError from './unauthorized-error';
import { EventHandler } from './interfaces/event_handling';
import {requestWithTimeout} from "./requests";
import {AuthorizeOptions} from "./interfaces/authorize_options";
import {Remote} from "./Remote";
import {Remote} from "./remote";


interface AuthResult {
Expand Down
36 changes: 13 additions & 23 deletions src/dropbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
generateCodeVerifier,
} from './util';
import {requestWithTimeout, isArrayBufferView, retryAfterMs} from "./requests";
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "./Remote";
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "./remote";
import RemoteStorage from "./remotestorage";
import Authorize from "./authorize";

Expand Down Expand Up @@ -282,7 +282,6 @@ class Dropbox extends RemoteBase implements Remote {
* @private
*/
_getFolder (path: string) {
const url = FOLDER_URL;
const revCache = this._revCache;

const processResponse = (resp) => {
Expand Down Expand Up @@ -334,15 +333,14 @@ class Dropbox extends RemoteBase implements Remote {
};

const loadNext = (cursor) => {
const continueURL = CONTINUE_URL;
const params = {
body: { cursor: cursor }
};

return this._request('POST', continueURL, params).then(processResponse);
return this._request('POST', CONTINUE_URL, params).then(processResponse);
};

return this._request('POST', url, {
return this._request('POST', FOLDER_URL, {
body: {
path: getDropboxPath(path)
}
Expand Down Expand Up @@ -371,8 +369,6 @@ class Dropbox extends RemoteBase implements Remote {
*/
get (path: string, options: { ifNoneMatch?: string } = {}): Promise<RemoteResponse> {
if (! this.connected) { return Promise.reject("not connected (path: " + path + ")"); }
const url = DOWNLOAD_URL;

const savedRev = this._revCache.get(path);
if (savedRev === null) {
// file was deleted server side
Expand Down Expand Up @@ -408,7 +404,7 @@ class Dropbox extends RemoteBase implements Remote {
params.headers['If-None-Match'] = options.ifNoneMatch;
}

return this._request('GET', url, params).then(resp => {
return this._request('GET', DOWNLOAD_URL, params).then(resp => {
const status = resp.status;
let meta, body, mime, rev;
if (status !== 200 && status !== 409) {
Expand Down Expand Up @@ -592,12 +588,11 @@ class Dropbox extends RemoteBase implements Remote {
* @private
*/
share (path: string): Promise<string> {
const url = CREATE_SHARED_URL;
const options = {
body: {path: getDropboxPath(path)}
};

return this._request('POST', url, options).then((response) => {
return this._request('POST', CREATE_SHARED_URL, options).then((response) => {
if (response.status !== 200 && response.status !== 409) {
return Promise.reject(new Error('Invalid response status:' + response.status));
}
Expand Down Expand Up @@ -641,9 +636,7 @@ class Dropbox extends RemoteBase implements Remote {
* @protected
*/
info (): Promise<{email: string}> {
const url = ACCOUNT_URL;

return this._request('POST', url, {}).then(function (response) {
return this._request('POST', ACCOUNT_URL, {}).then(function (response) {
let email;

try {
Expand Down Expand Up @@ -768,13 +761,14 @@ class Dropbox extends RemoteBase implements Remote {

/** This should resolve (with no value) on success, and reject on error. */
const fetch = async (cursor: string) => {
let url = FOLDER_URL;
let url;
let requestBody;

if (typeof cursor === 'string') {
url += '/continue';
url = CONTINUE_URL;
requestBody = { cursor };
} else {
url = FOLDER_URL;
requestBody = {
path: PATH_PREFIX,
recursive: true,
Expand Down Expand Up @@ -873,12 +867,11 @@ class Dropbox extends RemoteBase implements Remote {
* @private
*/
_getMetadata (path: string): Promise<Metadata> {
const url = METADATA_URL;
const requestBody = {
path: getDropboxPath(path)
};

return this._request('POST', url, { body: requestBody }).then((response) => {
return this._request('POST', METADATA_URL, { body: requestBody }).then((response) => {
if (response.status !== 200 && response.status !== 409) {
return Promise.reject(new Error('Invalid response status:' + response.status));
}
Expand Down Expand Up @@ -922,7 +915,6 @@ class Dropbox extends RemoteBase implements Remote {
* @private
*/
_uploadSimple (params: { body: XMLHttpRequestBodyInit; contentType?: string; path: string; ifMatch?: string; }): Promise<RemoteResponse> {
const url = UPLOAD_URL;
const args = {
path: getDropboxPath(params.path),
mode: { '.tag': 'overwrite', update: undefined },
Expand All @@ -933,7 +925,7 @@ class Dropbox extends RemoteBase implements Remote {
args.mode = { '.tag': 'update', update: params.ifMatch };
}

return this._request('POST', url, {
return this._request('POST', UPLOAD_URL, {
body: params.body,
headers: {
'Content-Type': 'application/octet-stream',
Expand Down Expand Up @@ -982,10 +974,9 @@ class Dropbox extends RemoteBase implements Remote {
* @private
*/
_deleteSimple (path: string): Promise<RemoteResponse> {
const url = DELETE_URL;
const requestBody = { path: getDropboxPath(path) };

return this._request('POST', url, { body: requestBody }).then((response) => {
return this._request('POST', DELETE_URL, { body: requestBody }).then((response) => {
if (response.status !== 200 && response.status !== 409) {
return Promise.resolve({statusCode: response.status});
}
Expand Down Expand Up @@ -1028,15 +1019,14 @@ class Dropbox extends RemoteBase implements Remote {
* @private
*/
async _getSharedLink (path: string): Promise<string> {
const url = LIST_SHARED_URL;
const options = {
body: {
path: getDropboxPath(path),
direct_only: true
}
};

return this._request('POST', url, options).then((response) => {
return this._request('POST', LIST_SHARED_URL, options).then((response) => {
if (response.status !== 200 && response.status !== 409) {
return Promise.reject(new Error('Invalid response status: ' + response.status));
}
Expand Down
2 changes: 1 addition & 1 deletion src/googledrive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
localStorageAvailable
} from './util';
import {requestWithTimeout, RequestOptions} from "./requests";
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "./Remote";
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "./remote";

const BASE_URL = 'https://www.googleapis.com';
const AUTH_URL = 'https://accounts.google.com/o/oauth2/auth';
Expand Down
127 changes: 127 additions & 0 deletions src/remote.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
import RemoteStorage from "./remotestorage";
import EventHandling from "./eventhandling";
import {isFolder} from "./util";

/**
* The ancestor for WireClient, GoogleDrive & Dropbox
*/
export class RemoteBase extends EventHandling {
rs: RemoteStorage;

connected: boolean;
online: boolean;
userAddress: string;
storageApi: string;

constructor(rs: RemoteStorage) {
super();
this.rs = rs;
this.connected = false;
// TODO: Should `online` be set true or false for all, here or in configure?
}

stopWaitingForToken (): void {
if (!this.connected) {
this._emit('not-connected');
}
}

addQuotes (str: string): string {
if (typeof (str) !== 'string') {
return str;
}
if (str === '*') {
return '*';
}

return '"' + str + '"';
}

stripQuotes (str: string): string {
if (typeof (str) !== 'string') {
return str;
}

return str.replace(/^["']|["']$/g, '');
}

isForbiddenRequestMethod(method: string, uri: string): boolean {
if (method === 'PUT' || method === 'DELETE') {
return isFolder(uri);
} else {
return false;
}
}
}


export interface RemoteSettings {
userAddress?: string;
href?: string; // remoteStorage server's base URL
storageApi?: string; // spec version
token?: string | false; // OAuth2 access token
refreshToken?: string; // OAuth2 refresh token
tokenType?: string; // type of access token; usually 'bearer'
properties?: object;
}

export interface RemoteResponse {
statusCode: number;
revision?: string;
contentType?: string;
body?: any;
}

/**
* The public interface for WireClient, GoogleDrive & Dropbox
*/
export interface Remote {
connected: boolean;
online: boolean;
userAddress: string;

/**
* Holds the spec version the server claims to be compatible with
*
* Example:
* (start code)
*
* remoteStorage.remote.storageApi
* // -> 'draft-dejong-remotestorage-01'
*/
storageApi: string;

/**
* Holds the server's base URL, as obtained in the Webfinger discovery
*
* Example:
* (start code)
*
* remoteStorage.remote.href
* // -> 'https://storage.example.com/users/jblogg/'
*/
href?: string;

/** the JSON-parsed properties object from the user's WebFinger record */
properties?: object;

clientId?: string; // OAuth2
TOKEN_URL?: string; // OAuth2 PKCE

configure (settings): void // TODO: harmonize settings & use type

configure (settings: RemoteSettings): void;

/**
* Initiate the authorization flow's OAuth dance.
*/
connect? (): void;

stopWaitingForToken (): void;

get (path: string, options: { ifMatch?: string; ifNoneMatch?: string }): Promise<RemoteResponse>;

put (path: string, body: XMLHttpRequestBodyInit, contentType: string, options: { ifMatch?: string; ifNoneMatch?: string }): Promise<RemoteResponse>

delete (path: string, options: { ifMatch?: string }): Promise<RemoteResponse>;
}
2 changes: 1 addition & 1 deletion src/remotestorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import Discover from './discover';
import SyncError from './sync-error';
import UnauthorizedError from './unauthorized-error';
import Features from './features';
import {Remote} from "./Remote";
import {Remote} from "./remote";

// TODO this is assigned to RemoteStorage.util later; check if still needed
import * as util from './util';
Expand Down
2 changes: 1 addition & 1 deletion src/wireclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import {
shouldBeTreatedAsBinary
} from './util';
import {requestWithTimeout, isArrayBufferView} from "./requests";
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "./Remote";
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "./remote";

let hasLocalStorage;
const SETTINGS_KEY = 'remotestorage:wireclient';
Expand Down
2 changes: 1 addition & 1 deletion test/unit/authorize.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import fetchMock from 'fetch-mock';
import {localStorageAvailable} from "../../src/util";
import RemoteStorage from '../../src/remotestorage';
import Authorize from '../../src/authorize';
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "../../src/Remote";
import {Remote, RemoteBase, RemoteResponse, RemoteSettings} from "../../src/remote";

chai.use(chaiAsPromised);

Expand Down
4 changes: 2 additions & 2 deletions test/unit/modules.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import 'mocha';
import { expect } from 'chai';
import RemoteStorage from '../../src/remotestorage';
import {Remote} from "../../src/Remote";
import {RemoteResponse, RemoteSettings} from "../../src/Remote";
import {Remote} from "../../src/remote";
import {RemoteResponse, RemoteSettings} from "../../src/remote";

describe('RemoteStorage module initialization', () => {
const env = {
Expand Down

0 comments on commit a688512

Please sign in to comment.