diff options
| -rw-r--r-- | ext/bg/js/backend.js | 45 | ||||
| -rw-r--r-- | ext/bg/js/options.js | 23 | ||||
| -rw-r--r-- | ext/bg/js/settings/anki.js | 10 | ||||
| -rw-r--r-- | ext/bg/js/settings/dictionaries.js | 12 | ||||
| -rw-r--r-- | ext/bg/js/util.js | 42 | ||||
| -rw-r--r-- | ext/fg/js/popup.js | 11 | ||||
| -rw-r--r-- | ext/mixed/js/api.js | 24 | ||||
| -rw-r--r-- | ext/mixed/js/core.js | 9 | 
8 files changed, 105 insertions, 71 deletions
| diff --git a/ext/bg/js/backend.js b/ext/bg/js/backend.js index 2265c1a9..04a3b932 100644 --- a/ext/bg/js/backend.js +++ b/ext/bg/js/backend.js @@ -100,7 +100,13 @@ class Backend {              ['getQueryParserTemplatesHtml', {handler: this._onApiGetQueryParserTemplatesHtml.bind(this), async: true}],              ['getZoom', {handler: this._onApiGetZoom.bind(this), async: true}],              ['getMessageToken', {handler: this._onApiGetMessageToken.bind(this), async: false}], -            ['getDefaultAnkiFieldTemplates', {handler: this._onApiGetDefaultAnkiFieldTemplates.bind(this), async: false}] +            ['getDefaultAnkiFieldTemplates', {handler: this._onApiGetDefaultAnkiFieldTemplates.bind(this), async: false}], +            ['getAnkiDeckNames', {handler: this._onApiGetAnkiDeckNames.bind(this), async: true}], +            ['getAnkiModelNames', {handler: this._onApiGetAnkiModelNames.bind(this), async: true}], +            ['getAnkiModelFieldNames', {handler: this._onApiGetAnkiModelFieldNames.bind(this), async: true}], +            ['getDictionaryInfo', {handler: this._onApiGetDictionaryInfo.bind(this), async: true}], +            ['getDictionaryCounts', {handler: this._onApiGetDictionaryCounts.bind(this), async: true}], +            ['purgeDatabase', {handler: this._onApiPurgeDatabase.bind(this), async: true}]          ]);          this._commandHandlers = new Map([ @@ -722,6 +728,36 @@ class Backend {          return this.defaultAnkiFieldTemplates;      } +    async _onApiGetAnkiDeckNames(params, sender) { +        this._validatePrivilegedMessageSender(sender); +        return await this.anki.getDeckNames(); +    } + +    async _onApiGetAnkiModelNames(params, sender) { +        this._validatePrivilegedMessageSender(sender); +        return await this.anki.getModelNames(); +    } + +    async _onApiGetAnkiModelFieldNames({modelName}, sender) { +        this._validatePrivilegedMessageSender(sender); +        return await this.anki.getModelFieldNames(modelName); +    } + +    async _onApiGetDictionaryInfo(params, sender) { +        this._validatePrivilegedMessageSender(sender); +        return await this.translator.database.getDictionaryInfo(); +    } + +    async _onApiGetDictionaryCounts({dictionaryNames, getTotal}, sender) { +        this._validatePrivilegedMessageSender(sender); +        return await this.translator.database.getDictionaryCounts(dictionaryNames, getTotal); +    } + +    async _onApiPurgeDatabase(params, sender) { +        this._validatePrivilegedMessageSender(sender); +        return await this.translator.purgeDatabase(); +    } +      // Command handlers      async _onCommandSearch(params) { @@ -818,6 +854,13 @@ class Backend {      // Utilities +    _validatePrivilegedMessageSender(sender) { +        const url = sender.url; +        if (!(typeof url === 'string' && yomichan.isExtensionUrl(url))) { +            throw new Error('Invalid message sender'); +        } +    } +      async _getAudioUri(definition, source, details) {          let optionsContext = (typeof details === 'object' && details !== null ? details.optionsContext : null);          if (!(typeof optionsContext === 'object' && optionsContext !== null)) { diff --git a/ext/bg/js/options.js b/ext/bg/js/options.js index f3e5f60d..da26b628 100644 --- a/ext/bg/js/options.js +++ b/ext/bg/js/options.js @@ -15,14 +15,23 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -/* global - * utilStringHashCode - */ -  /*   * Generic options functions   */ +function optionsGetStringHashCode(string) { +    let hashCode = 0; + +    if (typeof string !== 'string') { return hashCode; } + +    for (let i = 0, charCode = string.charCodeAt(i); i < string.length; charCode = string.charCodeAt(++i)) { +        hashCode = ((hashCode << 5) - hashCode) + charCode; +        hashCode |= 0; +    } + +    return hashCode; +} +  function optionsGenericApplyUpdates(options, updates) {      const targetVersion = updates.length;      const currentVersion = options.version; @@ -63,12 +72,12 @@ const profileOptionsVersionUpdates = [          options.anki.fieldTemplates = null;      },      (options) => { -        if (utilStringHashCode(options.anki.fieldTemplates) === 1285806040) { +        if (optionsGetStringHashCode(options.anki.fieldTemplates) === 1285806040) {              options.anki.fieldTemplates = null;          }      },      (options) => { -        if (utilStringHashCode(options.anki.fieldTemplates) === -250091611) { +        if (optionsGetStringHashCode(options.anki.fieldTemplates) === -250091611) {              options.anki.fieldTemplates = null;          }      }, @@ -87,7 +96,7 @@ const profileOptionsVersionUpdates = [      (options) => {          // Version 12 changes:          //  The preferred default value of options.anki.fieldTemplates has been changed to null. -        if (utilStringHashCode(options.anki.fieldTemplates) === 1444379824) { +        if (optionsGetStringHashCode(options.anki.fieldTemplates) === 1444379824) {              options.anki.fieldTemplates = null;          }      }, diff --git a/ext/bg/js/settings/anki.js b/ext/bg/js/settings/anki.js index b32a9517..ff1277ed 100644 --- a/ext/bg/js/settings/anki.js +++ b/ext/bg/js/settings/anki.js @@ -16,13 +16,13 @@   */  /* global + * apiGetAnkiDeckNames + * apiGetAnkiModelFieldNames + * apiGetAnkiModelNames   * getOptionsContext   * getOptionsMutable   * onFormOptionsChanged   * settingsSaveOptions - * utilAnkiGetDeckNames - * utilAnkiGetModelFieldNames - * utilAnkiGetModelNames   * utilBackgroundIsolate   */ @@ -107,7 +107,7 @@ async function _ankiDeckAndModelPopulate(options) {      const kanjiModel = {value: options.anki.kanji.model, selector: '#anki-kanji-model'};      try {          _ankiSpinnerShow(true); -        const [deckNames, modelNames] = await Promise.all([utilAnkiGetDeckNames(), utilAnkiGetModelNames()]); +        const [deckNames, modelNames] = await Promise.all([apiGetAnkiDeckNames(), apiGetAnkiModelNames()]);          deckNames.sort();          modelNames.sort();          termsDeck.values = deckNames; @@ -180,7 +180,7 @@ async function _onAnkiModelChanged(e) {      let fieldNames;      try {          const modelName = node.value; -        fieldNames = await utilAnkiGetModelFieldNames(modelName); +        fieldNames = await apiGetAnkiModelFieldNames(modelName);          _ankiSetError(null);      } catch (error) {          _ankiSetError(error); diff --git a/ext/bg/js/settings/dictionaries.js b/ext/bg/js/settings/dictionaries.js index 1a6d452b..7eed4273 100644 --- a/ext/bg/js/settings/dictionaries.js +++ b/ext/bg/js/settings/dictionaries.js @@ -17,8 +17,11 @@  /* global   * PageExitPrevention + * apiGetDictionaryCounts + * apiGetDictionaryInfo   * apiOptionsGet   * apiOptionsGetFull + * apiPurgeDatabase   * getOptionsContext   * getOptionsFullMutable   * getOptionsMutable @@ -27,10 +30,7 @@   * storageUpdateStats   * utilBackgroundIsolate   * utilDatabaseDeleteDictionary - * utilDatabaseGetDictionaryCounts - * utilDatabaseGetDictionaryInfo   * utilDatabaseImport - * utilDatabasePurge   */  let dictionaryUI = null; @@ -431,7 +431,7 @@ async function onDictionaryOptionsChanged() {  async function onDatabaseUpdated() {      try { -        const dictionaries = await utilDatabaseGetDictionaryInfo(); +        const dictionaries = await apiGetDictionaryInfo();          dictionaryUI.setDictionaries(dictionaries);          document.querySelector('#dict-warning').hidden = (dictionaries.length > 0); @@ -439,7 +439,7 @@ async function onDatabaseUpdated() {          updateMainDictionarySelectOptions(dictionaries);          await updateMainDictionarySelectValue(); -        const {counts, total} = await utilDatabaseGetDictionaryCounts(dictionaries.map((v) => v.title), true); +        const {counts, total} = await apiGetDictionaryCounts(dictionaries.map((v) => v.title), true);          dictionaryUI.setCounts(counts, total);      } catch (e) {          dictionaryErrorsShow([e]); @@ -618,7 +618,7 @@ async function onDictionaryPurge(e) {          dictionaryErrorsShow(null);          dictionarySpinnerShow(true); -        await utilDatabasePurge(); +        await apiPurgeDatabase();          for (const {options} of toIterable((await getOptionsFullMutable()).profiles)) {              options.dictionaries = utilBackgroundIsolate({});              options.general.mainDictionary = ''; diff --git a/ext/bg/js/util.js b/ext/bg/js/util.js index 69536f02..5edcc193 100644 --- a/ext/bg/js/util.js +++ b/ext/bg/js/util.js @@ -58,19 +58,6 @@ function utilBackgroundFunctionIsolate(func) {      return backgroundPage.utilFunctionIsolate(func);  } -function utilStringHashCode(string) { -    let hashCode = 0; - -    if (typeof string !== 'string') { return hashCode; } - -    for (let i = 0, charCode = string.charCodeAt(i); i < string.length; charCode = string.charCodeAt(++i)) { -        hashCode = ((hashCode << 5) - hashCode) + charCode; -        hashCode |= 0; -    } - -    return hashCode; -} -  function utilBackend() {      const backend = chrome.extension.getBackgroundPage().yomichanBackend;      if (!backend.isPrepared) { @@ -79,35 +66,6 @@ function utilBackend() {      return backend;  } -async function utilAnkiGetModelNames() { -    return utilIsolate(await utilBackend().anki.getModelNames()); -} - -async function utilAnkiGetDeckNames() { -    return utilIsolate(await utilBackend().anki.getDeckNames()); -} - -async function utilDatabaseGetDictionaryInfo() { -    return utilIsolate(await utilBackend().translator.database.getDictionaryInfo()); -} - -async function utilDatabaseGetDictionaryCounts(dictionaryNames, getTotal) { -    return utilIsolate(await utilBackend().translator.database.getDictionaryCounts( -        utilBackgroundIsolate(dictionaryNames), -        utilBackgroundIsolate(getTotal) -    )); -} - -async function utilAnkiGetModelFieldNames(modelName) { -    return utilIsolate(await utilBackend().anki.getModelFieldNames( -        utilBackgroundIsolate(modelName) -    )); -} - -async function utilDatabasePurge() { -    return utilIsolate(await utilBackend().translator.purgeDatabase()); -} -  async function utilDatabaseDeleteDictionary(dictionaryName, onProgress) {      return utilIsolate(await utilBackend().translator.database.deleteDictionary(          utilBackgroundIsolate(dictionaryName), diff --git a/ext/fg/js/popup.js b/ext/fg/js/popup.js index 42f08afa..99610e17 100644 --- a/ext/fg/js/popup.js +++ b/ext/fg/js/popup.js @@ -539,19 +539,10 @@ class Popup {          };      } -    static _isOnExtensionPage() { -        try { -            const url = chrome.runtime.getURL('/'); -            return window.location.href.substring(0, url.length) === url; -        } catch (e) { -            // NOP -        } -    } -      static async _injectStylesheet(id, type, value, useWebExtensionApi) {          const injectedStylesheets = Popup._injectedStylesheets; -        if (Popup._isOnExtensionPage()) { +        if (yomichan.isExtensionUrl(window.location.href)) {              // Permissions error will occur if trying to use the WebExtension API to inject              // into an extension page.              useWebExtensionApi = false; diff --git a/ext/mixed/js/api.js b/ext/mixed/js/api.js index 30c08347..7080d93a 100644 --- a/ext/mixed/js/api.js +++ b/ext/mixed/js/api.js @@ -116,6 +116,30 @@ function apiGetDefaultAnkiFieldTemplates() {      return _apiInvoke('getDefaultAnkiFieldTemplates');  } +function apiGetAnkiDeckNames() { +    return _apiInvoke('getAnkiDeckNames'); +} + +function apiGetAnkiModelNames() { +    return _apiInvoke('getAnkiModelNames'); +} + +function apiGetAnkiModelFieldNames(modelName) { +    return _apiInvoke('getAnkiModelFieldNames', {modelName}); +} + +function apiGetDictionaryInfo() { +    return _apiInvoke('getDictionaryInfo'); +} + +function apiGetDictionaryCounts(dictionaryNames, getTotal) { +    return _apiInvoke('getDictionaryCounts', {dictionaryNames, getTotal}); +} + +function apiPurgeDatabase() { +    return _apiInvoke('purgeDatabase'); +} +  function _apiInvoke(action, params={}) {      const data = {action, params};      return new Promise((resolve, reject) => { diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index 2d11c11a..6a3298fc 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -316,6 +316,15 @@ const yomichan = (() => {              this.trigger('orphaned', {error});          } +        isExtensionUrl(url) { +            try { +                const urlBase = chrome.runtime.getURL('/'); +                return url.substring(0, urlBase.length) === urlBase; +            } catch (e) { +                return false; +            } +        } +          getTemporaryListenerResult(eventHandler, userCallback, timeout=null) {              if (!(                  typeof eventHandler.addListener === 'function' && |