First pass migrating to manifest v3

This commit is contained in:
Marcel Klehr 2023-05-30 15:03:34 +02:00
parent ded6aa36ae
commit 8538e403e4
23 changed files with 275 additions and 207 deletions

View File

@ -1,11 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Floccus</title>
</head>
<body>
<script src="../../lib/chrome-promise.js"></script>
<script src="../js/background-script.js"></script>
</body>
</html>

View File

@ -1,83 +0,0 @@
/*!
* chrome-promise 1.0.7
* https://github.com/tfoxy/chrome-promise
*
* Copyright 2015 Tomás Fox
* Released under the MIT license
*/
(function(root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([], factory.bind(null, typeof exports === 'object' ? this : root));
} else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but
// only CommonJS-like environments that support module.exports,
// like Node.
module.exports = factory(this);
} else {
// Browser globals (root is window)
root.ChromePromise = factory(root);
}
}(this, function(root) {
'use strict';
var push = Array.prototype.push,
hasOwnProperty = Object.prototype.hasOwnProperty;
return ChromePromise;
////////////////
function ChromePromise(chrome, Promise) {
chrome = chrome || root.chrome;
Promise = Promise || root.Promise;
var runtime = chrome.runtime;
fillProperties(chrome, this);
////////////////
function setPromiseFunction(fn, thisArg) {
return function() {
var args = arguments;
return new Promise(function(resolve, reject) {
function callback() {
var err = runtime.lastError;
if (err) {
reject(err);
} else {
resolve.apply(null, arguments);
}
}
push.call(args, callback);
fn.apply(thisArg, args);
});
};
}
function fillProperties(source, target) {
for (var key in source) {
if (hasOwnProperty.call(source, key)) {
var val = source[key];
var type = typeof val;
if (type === 'object' && !(val instanceof ChromePromise) && key.indexOf('on') != 0) {
target[key] = {};
fillProperties(val, target[key]);
} else if (type === 'function') {
target[key] = setPromiseFunction(val, source);
} else {
target[key] = val;
}
}
}
}
}
}));

View File

@ -1,5 +1,5 @@
{
"manifest_version": 2,
"manifest_version": 3,
"name": "floccus bookmarks sync",
"short_name": "floccus",
"version": "4.19.1",
@ -19,18 +19,21 @@
"default_locale": "en",
"permissions": ["https://*/", "http://*/", "alarms", "bookmarks", "storage", "unlimitedStorage", "tabs", "identity"],
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self';",
"permissions": ["alarms", "bookmarks", "storage", "unlimitedStorage", "tabs", "identity"],
"host_permissions": [
"*://*/*"
],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self';"
},
"options_ui": {
"page": "dist/html/options.html",
"browser_style": false,
"chrome_style": false
"browser_style": false
},
"browser_action": {
"action": {
"browser_style": false,
"chrome_style": false,
"default_icon": {
"48": "icons/logo.png"
},
@ -39,6 +42,6 @@
},
"background": {
"page": "dist/html/background.html"
"service_worker": "dist/js/background-script.js"
}
}

27
package-lock.json generated
View File

@ -33,7 +33,6 @@
"intl-messageformat": "^9.9.1",
"js-base64": "^3.7.5",
"lodash": "^4.17.20",
"onwakeup": "^0.0.2",
"p-queue": "^5.0.0",
"punycode": "^2.1.1",
"random": "^2.2.0",
@ -4498,9 +4497,9 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001468",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz",
"integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==",
"version": "1.0.30001491",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001491.tgz",
"integrity": "sha512-17EYIi4TLnPiTzVKMveIxU5ETlxbSO3B6iPvMbprqnKh4qJsQGk5Nh1Lp4jIMAE0XfrujsJuWZAM3oJdMHaKBA==",
"dev": true,
"funding": [
{
@ -4510,6 +4509,10 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
]
},
@ -11269,11 +11272,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/onwakeup": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/onwakeup/-/onwakeup-0.0.2.tgz",
"integrity": "sha512-CNRpi/d+0Q9Ep+gn5L8eRLhKj9itLWnPk3cmYMz9SYlgUSB7HffRr0VkYuvPpCQ0tgFLVLFqlhbLvNao+Yqb4g=="
},
"node_modules/open": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",
@ -19662,9 +19660,9 @@
"dev": true
},
"caniuse-lite": {
"version": "1.0.30001468",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz",
"integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==",
"version": "1.0.30001491",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001491.tgz",
"integrity": "sha512-17EYIi4TLnPiTzVKMveIxU5ETlxbSO3B6iPvMbprqnKh4qJsQGk5Nh1Lp4jIMAE0XfrujsJuWZAM3oJdMHaKBA==",
"dev": true
},
"caseless": {
@ -24885,11 +24883,6 @@
"mimic-fn": "^4.0.0"
}
},
"onwakeup": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/onwakeup/-/onwakeup-0.0.2.tgz",
"integrity": "sha512-CNRpi/d+0Q9Ep+gn5L8eRLhKj9itLWnPk3cmYMz9SYlgUSB7HffRr0VkYuvPpCQ0tgFLVLFqlhbLvNao+Yqb4g=="
},
"open": {
"version": "8.4.2",
"resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz",

View File

@ -94,7 +94,6 @@
"intl-messageformat": "^9.9.1",
"js-base64": "^3.7.5",
"lodash": "^4.17.20",
"onwakeup": "^0.0.2",
"p-queue": "^5.0.0",
"punycode": "^2.1.1",
"random": "^2.2.0",
@ -111,6 +110,17 @@
"> 0.25%",
"last 2 versions and supports es6-generators",
"Firefox ESR",
"not dead"
"not dead",
"not bb >= 0",
"not and_chr >= 0",
"not and_ff >= 0",
"not and_qq >= 0",
"not and_uc >= 0",
"not ie_mob >= 0",
"not op_mini all",
"not op_mob >= 0",
"not Safari >= 0",
"not KaiOS >= 0",
"not Samsung >= 0"
]
}

View File

@ -1,8 +1,4 @@
import BrowserController from '../lib/browser/BrowserController'
window.controller = new BrowserController()
const onload = () => {
window.controller.onLoad()
}
window.addEventListener('load', onload)
const controller = new BrowserController()
controller.onLoad()

View File

@ -1,3 +1,2 @@
import app from '../ui'
app()

View File

@ -8,7 +8,7 @@ import IAccountStorage, { IAccountData, TAccountStrategy } from './interfaces/Ac
import { TAdapter } from './interfaces/Adapter'
import { IResource, TLocalTree } from './interfaces/Resource'
import Controller from './Controller'
import { Device } from '@capacitor/device'
import { Capacitor } from '@capacitor/core'
import IAccount from './interfaces/Account'
import Mappings from './Mappings'
@ -24,7 +24,7 @@ export default class Account {
static singleton : IAccount
static async getAccountClass(): Promise<IAccount> {
if ((await Device.getInfo()).platform === 'web') {
if (Capacitor.getPlatform() === 'web') {
this.singleton = (await import('./browser/BrowserAccount')).default
} else {
this.singleton = (await import('./native/NativeAccount')).default
@ -109,7 +109,8 @@ export default class Account {
async setData(data:IAccountData):Promise<void> {
const controller = await Controller.getSingleton()
await this.storage.setAccountData(data, controller.key)
const key = await controller.getKey()
await this.storage.setAccountData(data, key)
this.server.setData(data)
}

View File

@ -1,20 +1,106 @@
import { Device } from '@capacitor/device'
import IController from './interfaces/Controller'
export default class Controller {
export default class Controller implements IController {
static singleton: IController
static async getSingleton():Promise<IController> {
if (!this.singleton) {
if ((await Device.getInfo()).platform === 'web') {
const browser = (await import('./browser-api')).default
const background = await browser.runtime.getBackgroundPage()
this.singleton = background.controller
} else {
const NativeController = await import('./native/NativeController')
this.singleton = NativeController.default.getSingleton()
}
this.singleton = new Controller
}
return this.singleton
}
cancelSync(accountId, keepEnabled): Promise<void> {
return navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({type: 'cancelSync', params: [accountId, keepEnabled]})
})
}
onStatusChange(listener): () => void {
const eventListener = (event) => {
const {type} = event.data
if (type === 'onStatusChange') {
listener()
}
}
navigator.serviceWorker.addEventListener('message', eventListener)
return function() {
navigator.serviceWorker.removeEventListener('message', eventListener)
}
}
scheduleSync(accountId, wait): Promise<void> {
return navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({type: 'scheduleSync', params: [accountId, wait]})
})
}
setEnabled(enabled: boolean): void {
navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({type: 'setEnabled', params: [enabled]})
})
}
setKey(key): Promise<void> {
return navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({type: 'setKey', params: [key]})
})
}
syncAccount(accountId, strategy): Promise<void> {
return navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({type: 'setEnabled', params: [accountId, strategy]})
})
}
unlock(key): Promise<void> {
return navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({type: 'unlock', params: [key]})
})
}
unsetKey(): Promise<void> {
return navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({type: 'unsetKey', params: []})
})
}
getKey(): Promise<string|null> {
return new Promise((resolve) => {
const eventListener = (event) => {
if (event.data.type === 'getKeyResponse') {
resolve(event.data.params[0])
navigator.serviceWorker.removeEventListener('message', eventListener)
}
}
navigator.serviceWorker.addEventListener('message', eventListener)
navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({ type: 'getKey', params: [] })
})
})
}
getUnlocked(): Promise<boolean> {
return new Promise((resolve) => {
const eventListener = (event) => {
if (event.data.type === 'getUnlockedResponse') {
resolve(event.data.params[0])
navigator.serviceWorker.removeEventListener('message', eventListener)
}
}
navigator.serviceWorker.addEventListener('message', eventListener)
navigator.serviceWorker.ready.then((registration) => {
const worker = registration.active
worker.postMessage({ type: 'getUnlocked', params: [] })
})
})
}
}

View File

@ -1,11 +1,11 @@
/* global DEBUG */
import { Device } from '@capacitor/device'
import util from 'util'
import * as Parallel from 'async-parallel'
import packageJson from '../../package.json'
import Crypto from './Crypto'
import { Share } from '@capacitor/share'
import { Filesystem, Directory, Encoding } from '@capacitor/filesystem'
import { Capacitor } from '@capacitor/core'
export default class Logger {
static log() {
@ -17,7 +17,7 @@ export default class Logger {
}
static async persist() {
const Storage = ((await Device.getInfo()).platform === 'web') ? await import('./browser/BrowserAccountStorage') : await import('./native/NativeAccountStorage')
const Storage = (Capacitor.getPlatform() === 'web') ? await import('./browser/BrowserAccountStorage') : await import('./native/NativeAccountStorage')
await Storage.default.changeEntry(
'logs',
log => {
@ -30,7 +30,7 @@ export default class Logger {
}
static async getLogs() {
const Storage = ((await Device.getInfo()).platform === 'web') ? await import('./browser/BrowserAccountStorage') : await import('./native/NativeAccountStorage')
const Storage = (Capacitor.getPlatform() === 'web') ? await import('./browser/BrowserAccountStorage') : await import('./native/NativeAccountStorage')
return Storage.default.getEntry('logs', [])
}
@ -88,7 +88,7 @@ export default class Logger {
}
static async download(filename, blob) {
if ((await Device.getInfo()).platform === 'web') {
if (Capacitor.getPlatform() === 'web') {
const element = document.createElement('a')
let objectUrl = URL.createObjectURL(blob)

View File

@ -11,7 +11,7 @@ import {
OAuthTokenError
} from '../../errors/Error'
import { OAuth2Client } from '@byteowls/capacitor-oauth2'
import { Device } from '@capacitor/device'
import { Capacitor } from '@capacitor/core'
import { Http } from '@capacitor-community/http'
const OAuthConfig = {
@ -58,7 +58,7 @@ export default class GoogleDriveAdapter extends CachingAdapter {
}
static async authorize(interactive = true) {
const { platform } = await Device.getInfo()
const platform = Capacitor.getPlatform()
if (platform !== 'web') {
const result = await OAuth2Client.authenticate(OAuthConfig)
@ -134,7 +134,7 @@ export default class GoogleDriveAdapter extends CachingAdapter {
}
async getAccessToken(refreshToken:string) {
const {platform} = await Device.getInfo()
const platform = Capacitor.getPlatform()
const credentialType = platform
const response = await this.request('POST', 'https://oauth2.googleapis.com/token',

View File

@ -14,7 +14,7 @@ import {
SlashError
} from '../../errors/Error'
import { Http } from '@capacitor-community/http'
import { Device } from '@capacitor/device'
import { Capacitor } from '@capacitor/core'
import Html from '../serializers/Html'
const LOCK_INTERVAL = 2 * 60 * 1000 // Lock every 2mins while syncing
@ -283,8 +283,7 @@ export default class WebDavAdapter extends CachingAdapter {
}
async uploadFile(url, content_type, data) {
const info = await Device.getInfo()
if (info.platform === 'web') {
if (Capacitor.getPlatform() === 'web') {
return this.uploadFileWeb(url, content_type, data)
} else {
return this.uploadFileNative(url, content_type, data)
@ -352,8 +351,7 @@ export default class WebDavAdapter extends CachingAdapter {
}
async downloadFile(url) {
const info = await Device.getInfo()
if (info.platform === 'web') {
if (Capacitor.getPlatform() === 'web') {
return this.downloadFileWeb(url)
} else {
return this.downloadFileNative(url)

View File

@ -1,4 +1,63 @@
/* global ChromePromise chrome browser */
/* global chrome browser */
const ChromePromise = (function(root) {
'use strict'
var push = Array.prototype.push,
hasOwnProperty = Object.prototype.hasOwnProperty
return ChromePromise
function ChromePromise(chrome, Promise) {
chrome = chrome || root.chrome
Promise = Promise || root.Promise
var runtime = chrome.runtime
fillProperties(chrome, this)
/// /////////////
function setPromiseFunction(fn, thisArg) {
return function() {
var args = arguments
return new Promise(function(resolve, reject) {
function callback() {
var err = runtime.lastError
if (err) {
reject(err)
} else {
resolve.apply(null, arguments)
}
}
push.call(args, callback)
fn.apply(thisArg, args)
})
}
}
function fillProperties(source, target) {
for (var key in source) {
if (hasOwnProperty.call(source, key)) {
var val = source[key]
var type = typeof val
if (type === 'object' && !(val instanceof ChromePromise) && key.indexOf('on') !== 0) {
target[key] = {}
fillProperties(val, target[key])
} else if (type === 'function') {
target[key] = setPromiseFunction(val, source)
} else {
target[key] = val
}
}
}
}
}
})(this || window || self)
let b
if (typeof browser === 'undefined' && typeof chrome !== 'undefined') {
b = new ChromePromise()

View File

@ -13,12 +13,14 @@ import {
UnknownFolderItemOrderError
} from '../../errors/Error'
import {i18n} from '../native/I18n'
import Controller from '../Controller'
export default class BrowserAccount extends Account {
static async get(id:string):Promise<Account> {
const storage = new BrowserAccountStorage(id)
const background = await browser.runtime.getBackgroundPage()
const data = await storage.getAccountData(background.controller.key)
const controller = await Controller.getSingleton()
const key = await controller.getKey()
const data = await storage.getAccountData(key)
const tree = new BrowserTree(storage, data.localRoot)
return new BrowserAccount(id, storage, await AdapterFactory.factory(data), tree)
}
@ -28,8 +30,9 @@ export default class BrowserAccount extends Account {
const adapter = await AdapterFactory.factory(data)
const storage = new BrowserAccountStorage(id)
const background = await browser.runtime.getBackgroundPage()
await storage.setAccountData(data, background.controller.key)
const controller = await Controller.getSingleton()
const key = await controller.getKey()
await storage.setAccountData(data, key)
const tree = new BrowserTree(storage, data.localRoot)
return new BrowserAccount(id, storage, adapter, tree)
}
@ -68,8 +71,9 @@ export default class BrowserAccount extends Account {
}
async updateFromStorage():Promise<void> {
const background = await browser.runtime.getBackgroundPage()
const data = await this.storage.getAccountData(background.controller.key)
const controller = await Controller.getSingleton()
const key = await controller.getKey()
const data = await this.storage.getAccountData(key)
this.server.setData(data)
this.localTree = new BrowserTree(this.storage, data.localRoot)
}

View File

@ -6,7 +6,6 @@ import DefunctCryptography from '../DefunctCrypto'
import packageJson from '../../../package.json'
import BrowserAccountStorage from './BrowserAccountStorage'
import uniqBy from 'lodash/uniqBy'
import onwakeup from 'onwakeup'
import PQueue from 'p-queue'
import Account from '../Account'
@ -64,9 +63,6 @@ export default class BrowserController {
this.onchange(localId, details)
)
// Set up onWakeup
onwakeup(() => this.onWakeup())
// Set up the alarms
browser.alarms.create('checkSync', { periodInMinutes: 1 })
@ -114,6 +110,19 @@ export default class BrowserController {
// Set correct badge after waiting a bit
setTimeout(() => this.updateStatus(), 3000)
// Setup service worker messaging
this.onStatusChange(async() => {
const clientList = await self.clients.matchAll()
clientList.forEach(client => client.postMessage({type: 'onStatusChange', params: []}))
})
addEventListener('message', async(event) => {
const {type, params} = event.data
const result = await this[type](...params)
event.source.postMessage({type: type + 'Response', params: [result]})
})
}
setEnabled(enabled) {
@ -199,6 +208,14 @@ export default class BrowserController {
await Promise.all(accounts.map(a => a.setData(a.getData())))
}
getKey() {
return Promise.resolve(this.key)
}
getUnlocked() {
return Promise.resolve(this.unlocked)
}
async onchange(localId, details) {
if (!this.enabled) {
return
@ -373,13 +390,4 @@ export default class BrowserController {
})
)
}
async onWakeup() {
const accounts = await Account.getAllAccounts()
await Promise.all(
accounts.map(async acc => {
await acc.cancelSync()
})
)
}
}

View File

@ -90,7 +90,7 @@ export default class BrowserTree implements IResource {
})
folder.isRoot = isRoot
return folder
} else if (window.location.protocol === 'moz-extension:' && node.type === 'separator') {
} else if (self.location.protocol === 'moz-extension:' && node.type === 'separator') {
// Translate mozilla separators to floccus separators
return new Tree.Bookmark({
location: ItemLocation.LOCAL,
@ -121,7 +121,7 @@ export default class BrowserTree implements IResource {
return
}
try {
if (window.location.protocol === 'moz-extension:' && url.parse(bookmark.url).hostname === 'separator.floccus.org') {
if (self.location.protocol === 'moz-extension:' && url.parse(bookmark.url).hostname === 'separator.floccus.org') {
const node = await this.queue.add(() =>
browser.bookmarks.create({
parentId: bookmark.parentId,
@ -150,7 +150,7 @@ export default class BrowserTree implements IResource {
return
}
try {
if (window.location.protocol === 'moz-extension:' && url.parse(bookmark.url).hostname === 'separator.floccus.org') {
if (self.location.protocol === 'moz-extension:' && url.parse(bookmark.url).hostname === 'separator.floccus.org') {
// noop
} else {
await this.queue.add(() =>

View File

@ -1,14 +1,12 @@
export default interface IController {
key: string;
setEnabled(): void;
setEnabled(enabled:boolean): void;
setKey(key):Promise<void>;
unlock(key):Promise<void>;
unsetKey():Promise<void>;
onchange(localId, details):Promise<void>;
scheduleSync(accountId, wait):Promise<void>;
cancelSync(accountId, keepEnabled):Promise<void>;
syncAccount(accountId, strategy):Promise<void>;
updateStatus():Promise<void>;
onStatusChange(listener):()=>void;
onLoad():Promise<void>;
getKey():Promise<string|null>;
getUnlocked():Promise<boolean>;
}

View File

@ -20,7 +20,8 @@ export default class NativeAccount extends Account {
static async get(id:string):Promise<Account> {
const storage = new NativeAccountStorage(id)
const controller = await Controller.getSingleton()
const data = await storage.getAccountData(controller.key)
const key = await controller.getKey()
const data = await storage.getAccountData(key)
const tree = new NativeTree(storage)
await tree.load()
return new NativeAccount(id, storage, await AdapterFactory.factory(data), tree)
@ -32,7 +33,8 @@ export default class NativeAccount extends Account {
const storage = new NativeAccountStorage(id)
const controller = await Controller.getSingleton()
await storage.setAccountData(data, controller.key)
const key = await controller.getKey()
await storage.setAccountData(data, key)
const tree = new NativeTree(storage)
await tree.load()
return new NativeAccount(id, storage, adapter, tree)

View File

@ -5,7 +5,6 @@ import NativeAccountStorage from './NativeAccountStorage'
import PQueue from 'p-queue'
import Account from '../Account'
import onwakeup from 'onwakeup'
const INACTIVITY_TIMEOUT = 1000 * 7
const DEFAULT_SYNC_INTERVAL = 15
@ -54,9 +53,6 @@ export default class NativeController {
this.alarms = new AlarmManager(this)
// Set up onWakeup
onwakeup(() => this.onWakeup())
// lock accounts when locking is enabled
Storage.get({key: 'accountsLocked' }).then(async({value: accountsLocked}) => {
@ -66,6 +62,19 @@ export default class NativeController {
this.key = null
}
})
// Setup service worker messaging
this.onStatusChange(async() => {
const clientList = await self.clients.matchAll()
clientList.forEach(client => client.postMessage({type: 'onStatusChange', params: []}))
})
addEventListener('message', async(event) => {
const {type, params} = event.data
const result = await this[type](...params)
event.source.postMessage({type: type + 'Response', params: [result]})
})
}
setEnabled(enabled) {
@ -122,6 +131,14 @@ export default class NativeController {
await Promise.all(accounts.map(a => a.setData(a.getData())))
}
getKey() {
return Promise.resolve(this.key)
}
getUnlocked() {
return Promise.resolve(this.unlocked)
}
async scheduleSync(accountId, wait) {
if (wait) {
if (this.schedule[accountId]) {
@ -206,15 +223,6 @@ export default class NativeController {
})
)
}
async onWakeup() {
const accounts = await Account.getAllAccounts()
await Promise.all(
accounts.map(async acc => {
await acc.cancelSync()
})
)
}
}
let singleton

View File

@ -7,7 +7,7 @@ class XbelSerializer implements Serializer {
}
deserialize(xbel) {
const xmlDoc = new window.DOMParser().parseFromString(
const xmlDoc = new DOMParser().parseFromString(
xbel,
'application/xml'
)

View File

@ -46,7 +46,7 @@ export default class SyncProcess {
this.actionsDone = 0
this.actionsPlanned = 0
this.canceled = false
this.isFirefox = window.location.protocol === 'moz-extension:'
this.isFirefox = self.location.protocol === 'moz-extension:'
}
async cancel() :Promise<void> {

View File

@ -1,17 +1,12 @@
import { Device } from '@capacitor/device'
import { Capacitor } from '@capacitor/core'
import { App } from '@capacitor/app'
let deviceInfo = {}
Device.getInfo().then(info => {
deviceInfo.platform = info.platform
})
let backButtonListener = null
export default {
computed: {
isBrowser() {
return deviceInfo.platform === 'web' || !deviceInfo.platform
return Capacitor.getPlatform() === 'web' || !Capacitor.getPlatform()
},
},
mounted() {

View File

@ -10,8 +10,10 @@ import { Base64 } from 'js-base64'
export const actionsDefinition = {
async [actions.LOAD_LOCKED]({ commit, dispatch, state }) {
const controller = await Controller.getSingleton()
commit(mutations.SET_LOCKED, !controller.unlocked)
commit(mutations.SET_SECURED, typeof controller.key === 'string' || !controller.unlocked)
const key = await controller.getKey()
const unlocked = await controller.getUnlocked()
commit(mutations.SET_LOCKED, !unlocked)
commit(mutations.SET_SECURED, typeof key === 'string' || !unlocked)
},
async [actions.UNLOCK]({commit, dispatch, state}, key) {
const controller = await Controller.getSingleton()