Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ body:
- Linkwarden
- WebDAV
- Google Drive
- OneDrive
- Git
validations:
required: true
Expand Down
3 changes: 3 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ jobs:
- git-html
- google-drive
- google-drive-encrypted
- one-drive
- one-drive-encrypted
- linkwarden
- karakeep
test-name:
Expand Down Expand Up @@ -286,6 +288,7 @@ jobs:
FLOCCUS_TEST_SEED: ${{ github.sha }}
GIST_TOKEN: ${{ secrets.GIST_TOKEN }}
GOOGLE_API_REFRESH_TOKEN: ${{ secrets.GOOGLE_API_REFRESH_TOKEN }}
MICROSOFT_API_REFRESH_TOKEN: ${{ secrets.MICROSOFT_API_REFRESH_TOKEN }}
LINKWARDEN_TOKEN: ${{ secrets.LINKWARDEN_TOKEN }}
APP_VERSION: ${{ matrix.app-version }}
KARAKEEP_TEST_HOST: 172.17.0.1:3000
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![Tests](https://github.com/marcelklehr/floccus/workflows/Tests/badge.svg)](https://github.com/marcelklehr/floccus/actions?query=workflow%3ATests) <img src="https://img.shields.io/chrome-web-store/users/fnaicdffflnofjppbagibeoednhnbjhg.svg"> <img src="https://img.shields.io/amo/users/floccus.svg">

- 🔖 Syncs your real, native browser bookmarks directly
- ☸ Sync via [Nextcloud Bookmarks](https://github.com/nextcloud/bookmarks), [Linkwarden](https://linkwarden.app/), [KaraKeep](https://karakeep.app/), Google Drive, any Git server (like GitHub, Gitlab, Gitea, etc.) or [any WebDAV-compatible service](https://community.cryptomator.org/t/webdav-urls-of-common-cloud-storage-services/75)
- ☸ Sync via [Nextcloud Bookmarks](https://github.com/nextcloud/bookmarks), [Linkwarden](https://linkwarden.app/), [KaraKeep](https://karakeep.app/), Google Drive, OneDrive, any Git server (like GitHub, Gitlab, Gitea, etc.) or [any WebDAV-compatible service](https://community.cryptomator.org/t/webdav-urls-of-common-cloud-storage-services/75)
- ⚛ Use any browser that supports Web extensions (e.g. Firefox, Chrome, Edge, Opera, Brave, Vivaldi, ...; Safari [not yet](https://github.com/floccusaddon/floccus/issues/23))
- 📲 Install the floccus Android/iOS app to access your bookmarks on your phone (Most mobile browsers do not support floccus, sadly)
- 💼 Create as many sync profiles as you need
Expand Down
30 changes: 30 additions & 0 deletions _locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,15 @@
"Error050": {
"message": "E050: Failsafe: The current sync run would delete {0}% of your local links in this profile. Refusing to execute. Disable this failsafe in the profile settings if you want to proceed anyway."
},
"Error051": {
"message": "E051: Could not authenticate with OneDrive. Please connect floccus with your Microsoft account again."
},
"Error052": {
"message": "E052: OAuth error. Token validation error. Please reconnect your Microsoft Account."
},
"Error053": {
"message": "E053: Could not search for your file name in your OneDrive"
},
"LabelWebdavurl": {
"message": "WebDAV URL"
},
Expand All @@ -169,6 +178,9 @@
},
"DescriptionBookmarksfilegoogle": {
"message": "the file name of the bookmarks file that will reside in your Google Drive. Do not enter the full file path, only the file name. Make sure this name is unique in your Drive. e.g. mybookmarks.xbel"
},
"DescriptionBookmarksfileonedrive": {
"message": "the file name of the bookmarks file that will reside in your OneDrive. Do not enter the full file path, only the file name. Make sure this name is unique in your Drive. e.g. mybookmarks.xbel"
},
"DescriptionBookmarksfilegit": {
"message": "a path to the bookmarks file relative to your Git repository root (all folders in the path must already exist). e.g. personal_stuff/bookmarks.xbel"
Expand Down Expand Up @@ -567,6 +579,21 @@
"DescriptionLoggedingoogle": {
"message": "You have connected your Google account to store the bookmark sync file in your Google Drive."
},
"LabelAdapteronedrive": {
"message": "OneDrive"
},
"DescriptionAdapteronedrive": {
"message": "Sync bookmarks via an (optionally encrypted) file that is stored in your OneDrive. It can sync http, ftp, data, file and javascript bookmarks. You can choose to use end-to-end encryption when using this option."
},
"LabelLoginonedrive": {
"message": "Login with OneDrive"
},
"DescriptionLoginmicrosoft": {
"message": "Connect your Microsoft account to store the bookmark sync file in your OneDrive."
},
"DescriptionLoggedinmicrosoft": {
"message": "You have connected your Microsoft account to store the bookmark sync file in your OneDrive."
},
"LabelPassphrase": {
"message": "Passphrase"
},
Expand Down Expand Up @@ -699,6 +726,9 @@
"LabelGoogledrivesetup": {
"message": "Login to Google Drive"
},
"LabelOnedrivesetup": {
"message": "Login to OneDrive"
},
"LabelSyncfoldersetup": {
"message": "Which Folders do you want to sync?"
},
Expand Down
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
<data
android:host="@string/oauth_redirect_host"
android:scheme="@string/package_name" />
<data android:scheme="org.handmadeideas.floccus" android:host="auth" />
</intent-filter>
</activity>

Expand Down
2 changes: 1 addition & 1 deletion fastlane/metadata/android/en-US/full_description.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Manage and synchronize your bookmarks via Nextcloud, or any WebDAV service, or any Git service, or Google Drive, end-to-end encrypted, if you want.
Manage and synchronize your bookmarks via Nextcloud, or any WebDAV service, or any Git service, or Google Drive, or OneDrive, end-to-end encrypted, if you want.

This is the standalone bookmarks manager android app variant of floccus. You can also install floccus on your Desktop browsers to sync bookmarks with them. This App, due to technical reasons, cannot access bookmarks in your mobile browser apps directly, which is why you can only view them in the app or import and export them as a html file.

Expand Down
27 changes: 22 additions & 5 deletions google-api.credentials.json
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
{
"web":{
"client_id":"305459871054-4rr6n0jmsdvvprtjqbma5oeksshis2bn.apps.googleusercontent.com","project_id":"floccus-1613668481464","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","client_secret":"-2C9DALj2JYEGhZMZTvzN2ZE","redirect_uris":["https://mbepccofdnoepgicagpchfmafecckdam.chromiumapp.org/","https://76a380c4950986998208e7bb9dbd8fea94c91504.extensions.allizom.org/"]
"web": {
"client_id": "305459871054-4rr6n0jmsdvvprtjqbma5oeksshis2bn.apps.googleusercontent.com",
"project_id": "floccus-1613668481464",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "-2C9DALj2JYEGhZMZTvzN2ZE",
"redirect_uris": [
"https://mbepccofdnoepgicagpchfmafecckdam.chromiumapp.org/",
"https://76a380c4950986998208e7bb9dbd8fea94c91504.extensions.allizom.org/"
]
},
"android":{
"client_id":"305459871054-05e7kf9q9kkbeovaf380ldsb248psc2d.apps.googleusercontent.com","project_id":"floccus-1613668481464","auth_uri":"https://accounts.google.com/o/oauth2/auth","token_uri":"https://oauth2.googleapis.com/token","auth_provider_x509_cert_url":"https://www.googleapis.com/oauth2/v1/certs","redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]
"android": {
"client_id": "305459871054-05e7kf9q9kkbeovaf380ldsb248psc2d.apps.googleusercontent.com",
"project_id": "floccus-1613668481464",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"redirect_uris": [
"urn:ietf:wg:oauth:2.0:oob",
"http://localhost"
]
},
"ios": {
"client_id": "305459871054-ovvunbhc8jf8g467gtpsbnap5el302gq.apps.googleusercontent.com"
}
}
}
21 changes: 7 additions & 14 deletions gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,20 +13,13 @@ var path = require('path')
try {
fs.accessSync('./google-api.credentials.json')
} catch (e) {
fs.writeFileSync('./google-api.credentials.json', JSON.stringify({
'web': {
'client_id': 'yourappidhere.apps.googleusercontent.com',
'project_id': 'YOUR PROJECT ID HERE',
'auth_uri': 'https://accounts.google.com/o/oauth2/auth',
'token_uri': 'https://oauth2.googleapis.com/token',
'auth_provider_x509_cert_url': 'https://www.googleapis.com/oauth2/v1/certs',
'client_secret': 'YOUR CLIENT SECRET HERE',
'redirect_uris': [
'https://yourappidhere.chromiumapp.org/',
'https://yourappidhere.extensions.allizom.org/'
]
}
}))
console.log(`error loading google api credentials: ${e.message}`)
}

try {
fs.accessSync('./onedrive-api.credentials.json')
} catch (e) {
console.log(`error loading onedrive api credentials: ${e.message}`)
}

// eslint-disable-next-line @typescript-eslint/no-var-requires
Expand Down
4 changes: 1 addition & 3 deletions manifest.firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,11 @@

"options_ui": {
"page": "dist/html/options.html",
"browser_style": false,
"chrome_style": false
"browser_style": false
},

"browser_action": {
"browser_style": false,
Comment thread
aaryanvangari marked this conversation as resolved.
"chrome_style": false,
"default_icon": {
"48": "icons/logo.png"
},
Expand Down
27 changes: 27 additions & 0 deletions onedrive-api.credentials.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"web": {
"client_id": "635108ad-2d58-480a-a6cf-7955020a76a1",
"project_id": "635108ad-2d58-480a-a6cf-7955020a76a1",
"auth_uri": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
"token_uri": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
"client_secret": "",
"redirect_uris": [
"https://mbepccofdnoepgicagpchfmafecckdam.chromiumapp.org/",
"https://76a380c4950986998208e7bb9dbd8fea94c91504.extensions.allizom.org/",
"https://fnaicdffflnofjppbagibeoednhnbjhg.chromiumapp.org/",
"https://gjkddcofhiifldbllobcamllmanombji.chromiumapp.org/",
"https://djejpebekaoommcjfeaiipdikmdjkblg.chromiumapp.org/"
]
},
"android": {
"client_id": "635108ad-2d58-480a-a6cf-7955020a76a1",
"project_id": "635108ad-2d58-480a-a6cf-7955020a76a1",
"auth_uri": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize",
"token_uri": "https://login.microsoftonline.com/common/oauth2/v2.0/token",
"redirect_uri": "org.handmadeideas.floccus://auth"
},
"ios": {
"client_id": "635108ad-2d58-480a-a6cf-7955020a76a1",
"redirect_uri": "org.handmadeideas.floccus://auth"
}
}
30 changes: 27 additions & 3 deletions src/errors/Error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,11 @@ export class GoogleDriveAuthenticationError extends FloccusError {
}
}

export class OAuthTokenError extends FloccusError {
export class GoogleOAuthTokenError extends FloccusError {
public readonly code = 32
constructor() {
super('E032: OAuth error. Token validation error. Please reconnect your Google Account.')
Object.setPrototypeOf(this, OAuthTokenError.prototype)
Object.setPrototypeOf(this, GoogleOAuthTokenError.prototype)
}
}

Expand Down Expand Up @@ -462,4 +462,28 @@ export class ClientsideDeletionFailsafeError extends FloccusError {
this.percent = percent
Object.setPrototypeOf(this, ClientsideDeletionFailsafeError.prototype)
}
}
}

export class OneDriveAuthenticationError extends FloccusError {
public readonly code = 51
constructor() {
super('E051: Could not authenticate with OneDrive. Please connect floccus with your OneDrive account again.')
Object.setPrototypeOf(this, OneDriveAuthenticationError.prototype)
}
}

export class OneDriveOAuthTokenError extends FloccusError {
public readonly code = 52
constructor() {
super('E052: OAuth error. Token validation error. Please reconnect your OneDrive Account.')
Object.setPrototypeOf(this, OneDriveOAuthTokenError.prototype)
}
}

export class OneDriveSearchError extends FloccusError {
public readonly code = 53
constructor() {
super('E053: Could not search for your file name in your OneDrive')
Object.setPrototypeOf(this, OneDriveSearchError.prototype)
}
}
3 changes: 2 additions & 1 deletion src/lib/Account.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ AdapterFactory.register('nextcloud-folders', async() => (await import('./adapter
AdapterFactory.register('nextcloud-bookmarks', async() => (await import('./adapters/NextcloudBookmarks')).default)
AdapterFactory.register('webdav', async() => (await import('./adapters/WebDav')).default)
AdapterFactory.register('git', async() => (await import('./adapters/Git')).default)
AdapterFactory.register('google-drive', async() => (await import('./adapters/GoogleDrive')).default)
AdapterFactory.register('google-drive', async () => (await import('./adapters/GoogleDrive')).default)
AdapterFactory.register('one-drive', async() => (await import('./adapters/OneDrive')).default)
AdapterFactory.register('fake', async() => (await import('./adapters/Fake')).default)

// 2h
Expand Down
15 changes: 15 additions & 0 deletions src/lib/Crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,19 @@ export default class Crypto {
crypto.getRandomValues(rand)
return rand
}

static base64UrlEncode(data: ArrayBuffer | Uint8Array) {
const bytes = data instanceof Uint8Array ? data : new Uint8Array(data)

return btoa(String.fromCharCode(...bytes))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}

static async generatePKCECodeChallenge(verifier: string) {
const data = new TextEncoder().encode(verifier)
const digest = await crypto.subtle.digest('SHA-256', data)
return this.base64UrlEncode(digest)
}
}
8 changes: 4 additions & 4 deletions src/lib/adapters/GoogleDrive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
DecryptionError, FileUnreadableError,
GoogleDriveAuthenticationError, HttpError, CancelledSyncError, MissingPermissionsError,
NetworkError,
OAuthTokenError, ResourceLockedError, GoogleDriveSearchError, RequestTimeoutError
GoogleOAuthTokenError, ResourceLockedError, GoogleDriveSearchError, RequestTimeoutError
} from '../../errors/Error'
import { OAuth2Client } from '@byteowls/capacitor-oauth2'
import { Capacitor, CapacitorHttp as Http } from '@capacitor/core'
Expand Down Expand Up @@ -123,12 +123,12 @@ export default class GoogleDriveAdapter extends CachingAdapter {

if (response.status !== 200) {
Logger.log('Failed to retrieve refresh token from Google API: ' + await response.text())
throw new OAuthTokenError()
throw new GoogleOAuthTokenError()
}
const json = await response.json()
if (!json.access_token || !json.refresh_token) {
Logger.log('Failed to retrieve refresh token from Google API: ' + JSON.stringify(json))
throw new OAuthTokenError()
throw new GoogleOAuthTokenError()
}

const res = await fetch('https://www.googleapis.com/drive/v3/about?fields=user/displayName', {
Expand Down Expand Up @@ -162,7 +162,7 @@ export default class GoogleDriveAdapter extends CachingAdapter {
if (json.access_token) {
return json.access_token
} else {
throw new OAuthTokenError()
throw new GoogleOAuthTokenError()
}
}

Expand Down
Loading