Merge branch 'develop'

This commit is contained in:
SamTV12345 2024-02-05 20:17:01 +01:00
commit 6814aa9a3c
29 changed files with 592 additions and 214 deletions

View file

@ -17,4 +17,4 @@ jobs:
- name: 'Checkout Repository'
uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v3
uses: actions/dependency-review-action@v4

View file

@ -89,3 +89,11 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
- name: Update repo description
uses: peter-evans/dockerhub-description@v4
if: github.ref == 'refs/heads/master'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: etherpad/etherpad
enable-url-completion: true

1
.gitignore vendored
View file

@ -21,3 +21,4 @@ out/
/src/bin/convertSettings.json
/src/bin/etherpad-1.deb
/src/bin/node.exe
plugin_packages

View file

@ -1,3 +1,12 @@
# 1.9.7
### Notable enhancements and fixes
* Added Live Plugin Manager: Plugins are now installed into a separate folder on the host system. This folder is called `plugin_packages`.
That way the plugins are separated from the normal etherpad installation.
* Make repairPad.js more verbose
* Fixed favicon not being loaded correctly
# 1.9.6
### Notable enhancements and fixes
@ -9,7 +18,7 @@
# 1.9.5
### Compability changes
### Compatibility changes
* This version deprecates NodeJS16 as it reached its end of life and won't receive any updates. So to get started with Etherpad v1.9.5 you need NodeJS 18 and above.
* The bundled windows NodeJS version has been bumped to the current LTS version 20.
@ -21,7 +30,7 @@
# 1.9.4
### Compability changes
### Compatibility changes
* Log4js has been updated to the latest version. As it involved a bump of 6 major version.
A lot has changed since then. Most notably the console appender has been deprecated. You can find out more about it [here](https://github.com/log4js-node/log4js-node)

View file

@ -1049,8 +1049,7 @@ Context properties:
* `srcFile`: The document to convert.
* `ImportError`: Subclass of Error that can be thrown to provide a specific
error message to the user. The constructor's first argument must be a string
matching one of the [known error
identifiers](https://github.com/ether/etherpad-lite/blob/1.8.16/src/static/js/pad_impexp.js==L80-L86).
matching one of the https://github.com/ether/etherpad-lite/blob/1.9.6/src/static/js/pad_impexp.js#L80-L86[known error identifiers].
Example:

View file

@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"marked": {
"version": "11.1.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-11.1.0.tgz",
"integrity": "sha512-fvKJWAPEafVj1dwGwcPI5mBB/0pvViL6NlCbNDG1HOIRwwAU/jeMoFxfbRLuirO1wRH7m4yPvBqD/O1wyWvayw=="
"version": "11.2.0",
"resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz",
"integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw=="
}
}
}

View file

@ -7,7 +7,7 @@
"node": ">=12.17.0"
},
"dependencies": {
"marked": "^11.1.0"
"marked": "^11.2.0"
},
"devDependencies": {},
"optionalDependencies": {},

View file

@ -0,0 +1,16 @@
#!/bin/bash
# Specify the path to your package.json file
PACKAGE_JSON_PATH="./src//package.json"
# Check if the file exists
if [ ! -f "$PACKAGE_JSON_PATH" ]; then
echo "Error: package.json not found in the specified path."
exit 1
fi
# Read the version from package.json into a variable
VERSION=$(jq -r '.version' "$PACKAGE_JSON_PATH")
git push origin master develop $VERSION
git push --tags
(cd ../ether.github.com && git push)

View file

@ -207,11 +207,10 @@ console.log(' git log --graph --date-order --boundary --oneline --decorate deve
console.log(` git show '${newVersion}'`);
console.log(' (cd ../ether.github.com && git show)');
console.log('If everything looks good then push:');
console.log(` git push origin master develop '${newVersion}'`);
console.log(' (cd ../ether.github.com && git push)');
console.log('Run ./bin/push-after-release.sh');
console.log('Creating a Windows build is not necessary anymore and will be created by GitHub action');
console.log('Visit https://github.com/ether/etherpad-lite/releases/new and create a new release ' +
`with 'master' as the target and the version is ${newVersion}. `);
console.log('After the windows binary is created a new release with the set version is created automatically.' +
' Just paste the release notes in there');
console.log('The docs are updated automatically with the new version. While the windows build' +
' is generated people can still download the older versions.');
console.log('Finally go public with an announcement via our comms channels :)');

View file

@ -43,7 +43,9 @@ let valueCount = 0;
neededDBValues.push(`pad:${padId}:chat:${chat}`);
}
// now fetch and reinsert every key
console.log('Fetch and reinsert every key');
for (const key of neededDBValues) {
if (valueCount % 100 === 0) console.log(valueCount + "/" + neededDBValues.length);
const value = await db.get(key);
// if it isn't a globalAuthor value which we want to ignore..
// console.log(`Key: ${key}, value: ${JSON.stringify(value)}`);

View file

@ -15,9 +15,9 @@
},
"index.newPad": "Yeni lövhə",
"index.createOpenPad": "və ya lövhəni bu adla yarat/aç:",
"pad.toolbar.bold.title": "Qalın (Ctrl-B)",
"pad.toolbar.italic.title": "Kursiv (Ctrl-I)",
"pad.toolbar.underline.title": "Altından xətt çəkmə (Ctrl-U)",
"pad.toolbar.bold.title": "Qalın (Ctrl+B)",
"pad.toolbar.italic.title": "Kursiv (Ctrl+I)",
"pad.toolbar.underline.title": "Altından xətt çəkmə (Ctrl+U)",
"pad.toolbar.strikethrough.title": "Üstdən xətləmək (Ctrl+5)",
"pad.toolbar.ol.title": "Sıralanmış siyahı (Ctrl+Shift+N)",
"pad.toolbar.ul.title": "Sırasız siyahı (Ctrl+Shift+L)",

View file

@ -3,6 +3,7 @@
"authors": [
"Aftab1995",
"Aftabuzzaman",
"Aishik Rehman",
"Al Riaz Uddin Ripon",
"Bellayet",
"Greatder",
@ -84,7 +85,7 @@
"pad.settings.about": "পরিচিতি",
"pad.settings.poweredBy": "এটি দ্বারা চালিত:",
"pad.importExport.import_export": "আমদানি/রপ্তানি",
"pad.importExport.import": "কোন টেক্সট ফাইল বা নথি আপলোড করুন",
"pad.importExport.import": "কোন টেক্সট ফাইল বা নথি আপলোড করুন",
"pad.importExport.importSuccessful": "সফল!",
"pad.importExport.export": "এইরূপে এই প্যাডটি রপ্তানি করুন:",
"pad.importExport.exportetherpad": "ইথারপ্যাড",
@ -150,7 +151,7 @@
"timeslider.unnamedauthors": "নামবিহীন {{num}} জন {[plural(num) one: লেখক, other: লেখক ]}",
"pad.savedrevs.marked": "এই সংশোধনটি এখন সংরক্ষিত সংশোধন হিসেবে চিহ্নিত করা হয়েছে",
"pad.userlist.entername": "আপনার নাম লিখুন",
"pad.userlist.unnamed": "কোন নাম নির্বাচন করা হয়নি",
"pad.userlist.unnamed": "কোন নাম নির্বাচন করা হয়নি",
"pad.impexp.importbutton": "এখন আমদানি করুন",
"pad.impexp.importing": "আমদানি হচ্ছে...",
"pad.impexp.padHasData": "আমরা এই ফাইলটি আমদানি করতে সক্ষম হয়নি কারণ এই প্যাড ইতিমধ্যে পরিবর্তিত হয়েছে, দয়া করে একটি নতুন প্যাডে অামদানি করুন।",

View file

@ -77,8 +77,8 @@
"pad.permissionDenied": "Du hast keine Berechtigung, um auf dieses Pad zuzugreifen.",
"pad.settings.padSettings": "Pad-Einstellungen",
"pad.settings.myView": "Eigene Ansicht",
"pad.settings.stickychat": "Unterhaltung immer anzeigen",
"pad.settings.chatandusers": "Unterhaltung und Benutzer anzeigen",
"pad.settings.stickychat": "Chat immer anzeigen",
"pad.settings.chatandusers": "Chat und Benutzer anzeigen",
"pad.settings.colorcheck": "Autorenfarben anzeigen",
"pad.settings.linenocheck": "Zeilennummern",
"pad.settings.rtlcheck": "Inhalt von rechts nach links lesen?",
@ -132,7 +132,7 @@
"pad.share.readonly": "Eingeschränkter Nur-Lese-Zugriff",
"pad.share.link": "Verknüpfung",
"pad.share.emebdcode": "In Webseite einbetten",
"pad.chat": "Unterhaltung",
"pad.chat": "Chat",
"pad.chat.title": "Den Chat für dieses Pad öffnen.",
"pad.chat.loadmessages": "Weitere Nachrichten laden",
"pad.chat.stick.title": "Chat an den Bildschirm anheften",

View file

@ -64,6 +64,7 @@
"pad.modals.unauth.explanation": "Är Rechter hu geännert während deem Dir dës säit gekuckt hutt. Probéiert fir Iech nei ze connectéieren.",
"pad.modals.looping.explanation": "Et gëtt Kommunikatiounsproblemer mam Synchronisatiouns-Server.",
"pad.modals.initsocketfail": "De Server kann net erreecht ginn.",
"pad.modals.initsocketfail.explanation": "Et konnt keng Verbindung mam Synchronisatiounsserver opgeholl ginn.",
"pad.modals.slowcommit.explanation": "De Server äntwert net.",
"pad.modals.deleted": "Geläscht.",
"pad.modals.deleted.explanation": "Dëse Pad gouf geläscht.",

View file

@ -2,6 +2,7 @@
"@metadata": {
"authors": [
"DeRudySoulStorm",
"Iketsi",
"Kareyac",
"Macofe",
"Mateon1",
@ -15,8 +16,19 @@
"Woytecr"
]
},
"admin.page-title": "Panel administracyjny Etherpad",
"admin_plugins": "Menedżer wtyczek",
"admin_plugins.available": "Dostępne wtyczki",
"admin_plugins.available_not-found": "Nie znaleziono żadnych wtyczek.",
"admin_plugins.available_install.value": "Instaluj",
"admin_plugins.description": "Opis",
"admin_plugins.installed": "Zainstalowane wtyczki",
"admin_plugins.installed_uninstall.value": "Odinstaluj",
"admin_plugins.last-update": "Ostatnia aktualizacja",
"admin_plugins.name": "Nazwa",
"admin_plugins.page-title": "Menedżer wtyczek - Etherpad",
"admin_plugins.version": "Wersja",
"admin_plugins_info.version": "Wersja Etherpada",
"admin_settings": "Ustawienia",
"index.newPad": "Nowy dokument",
"index.createOpenPad": "lub stwórz/otwórz dokument o nazwie:",

View file

@ -12,6 +12,7 @@
"Movses",
"Nzeemin",
"Okras",
"Pacha Tchernof",
"Patrick Star",
"Teretalexev",
"Volkov",
@ -73,7 +74,7 @@
"pad.toolbar.showusers.title": "Показать пользователей в документе",
"pad.colorpicker.save": "Сохранить",
"pad.colorpicker.cancel": "Отмена",
"pad.loading": "Загрузка...",
"pad.loading": "Загружается…",
"pad.noCookie": "Куки не найдены. Пожалуйста, включите куки в вашем браузере! Ваш сеанс и настройки не будут сохранены между посещениями. Это может быть связано с тем, что Etherpad включен в iFrame в некоторых браузерах. Убедитесь, что Etherpad находится в том же поддомене/домене, что и родительский iFrame.",
"pad.permissionDenied": "У вас нет разрешения на доступ",
"pad.settings.padSettings": "Настройки документа",

View file

@ -5,6 +5,7 @@
"Cosing",
"Dimension",
"GuoPC",
"HellojoeAoPS",
"Hydra",
"Hzy980512",
"JuneAugust",
@ -28,20 +29,20 @@
"admin_plugins.available_not-found": "找不到插件。",
"admin_plugins.available_fetching": "获取中…",
"admin_plugins.available_install.value": "安装",
"admin_plugins.available_search.placeholder": "搜索插件以安装",
"admin_plugins.available_search.placeholder": "搜索要安装的插件",
"admin_plugins.description": "描述",
"admin_plugins.installed": "已装插件",
"admin_plugins.installed_fetching": "正在获取已安装的插件…",
"admin_plugins.installed_nothing": "您尚未安装任何插件。",
"admin_plugins.installed_uninstall.value": "卸载",
"admin_plugins.last-update": "最更新",
"admin_plugins.last-update": "最更新",
"admin_plugins.name": "名称",
"admin_plugins.page-title": "插件管理器 - Etherpad",
"admin_plugins.version": "版本",
"admin_plugins_info": "故障排除信息",
"admin_plugins_info.hooks": "已安装的",
"admin_plugins_info.hooks_client": "客户端",
"admin_plugins_info.hooks_server": "服务器端",
"admin_plugins_info.hooks": "已安装的钩",
"admin_plugins_info.hooks_client": "客户端钩",
"admin_plugins_info.hooks_server": "服务器端钩",
"admin_plugins_info.parts": "已安装部分",
"admin_plugins_info.plugins": "已安装插件",
"admin_plugins_info.page-title": "插件信息 - Etherpad",
@ -56,7 +57,7 @@
"admin_settings.current_save.value": "保存设置",
"admin_settings.page-title": "设置 - Etherpad",
"index.newPad": "新记事本",
"index.createOpenPad": "或者创建/打开带名字的记事本:",
"index.createOpenPad": "或创建/打开一个名为以下的记事本:",
"index.openPad": "打开一个现有的记事本,名称为:",
"pad.toolbar.bold.title": "粗体Ctrl-B",
"pad.toolbar.italic.title": "斜体Ctrl-I",
@ -64,7 +65,7 @@
"pad.toolbar.strikethrough.title": "删除线Ctrl+5",
"pad.toolbar.ol.title": "有序列表Ctrl+Shift+N",
"pad.toolbar.ul.title": "无序列表Ctrl+Shift+L",
"pad.toolbar.indent.title": "增加缩进TAB",
"pad.toolbar.indent.title": "缩进TAB",
"pad.toolbar.unindent.title": "减少缩进Shift+TAB",
"pad.toolbar.undo.title": "撤消Ctrl-Z",
"pad.toolbar.redo.title": "重做Ctrl+Y",
@ -78,7 +79,7 @@
"pad.colorpicker.save": "保存",
"pad.colorpicker.cancel": "取消",
"pad.loading": "加载中...",
"pad.noCookie": "无法找到Cookie。请在您的浏览器中允许Cookie您的会话和设置不会在访问时保存。这可能是由于Etherpad包含在某些浏览器中的iFrame中。请确保Etherpad与父iFrame位于同一子域/域上",
"pad.noCookie": "无法找到 Cookie。请在您的浏览器中允许cookie您的会话和设置不会在两次访问之间保存。这可能是由于 Etherpad 包含在某些浏览器的 iFrame 中。请确保 Etherpad 与父 iFrame 位于同一子域/域中",
"pad.permissionDenied": "您没有访问这个记事本的权限",
"pad.settings.padSettings": "记事本设置",
"pad.settings.myView": "我的视窗",
@ -110,7 +111,7 @@
"pad.modals.cancel": "取消",
"pad.modals.userdup": "在另一个窗口中打开",
"pad.modals.userdup.explanation": "此记事本似乎在本电脑上的多个浏览器窗口中打开。",
"pad.modals.userdup.advice": "重新连接,使用此窗口。",
"pad.modals.userdup.advice": "重新连接以使用此窗口替代。",
"pad.modals.unauth": "未授权",
"pad.modals.unauth.explanation": "您的权限在查看此页面时已改变。尝试重新连接。",
"pad.modals.looping.explanation": "与同步服务器的通信出现问题。",
@ -121,17 +122,17 @@
"pad.modals.slowcommit.explanation": "服务器没有响应。",
"pad.modals.slowcommit.cause": "这可能是由于网络连接问题。",
"pad.modals.badChangeset.explanation": "您的一个编辑被同步服务器分类为非法。",
"pad.modals.badChangeset.cause": "这可能是因为服务器配置的错误或者其他未预料到的行为。如果您认为这是错误,请联系服务管理员。要继续编辑,请尝试重新连接。",
"pad.modals.badChangeset.cause": "这可能是由于服务器配置错误或其他一些意外行为造成的。如果您认为这是一个错误,请联系服务管理员。尝试重新连接以继续编辑。",
"pad.modals.corruptPad.explanation": "您试图连接的记事本已损坏。",
"pad.modals.corruptPad.cause": "这可能是因为服务器配置的错误或者其他未预料到的行为。请联系服务管理员。",
"pad.modals.corruptPad.cause": "这可能是由于服务器配置错误或其他一些意外行为造成的。请联系服务管理员。",
"pad.modals.deleted": "已删除。",
"pad.modals.deleted.explanation": "此记事本已被移除。",
"pad.modals.rateLimited": "速率限制",
"pad.modals.rateLimited.explanation": "您向此记事本发送了太多消息,因此中断了与您的连接。",
"pad.modals.rateLimited": "费率有限。",
"pad.modals.rateLimited.explanation": "您向此平板发送了太多消息,因此它断开了您的连接。",
"pad.modals.rejected.explanation": "服务器拒绝了您的浏览器发送的信息。",
"pad.modals.rejected.cause": "服务器可能在你查看页面时更新了也可能是Etherpad出现了错误。请尝试重新加载页面。",
"pad.modals.rejected.cause": "服务器可能在你查看记事本时更新了也可能是Etherpad出现了错误。请尝试重新加载页面。",
"pad.modals.disconnected": "您已断开连接。",
"pad.modals.disconnected.explanation": "到服务器的连接已丢失",
"pad.modals.disconnected.explanation": "与服务器的连接丢失",
"pad.modals.disconnected.cause": "服务器可能无法使用。若此情况持续发生,请通知服务器管理员。",
"pad.share": "分享此记事本",
"pad.share.readonly": "只读",
@ -141,8 +142,8 @@
"pad.chat.title": "打开此记事本的聊天窗口。",
"pad.chat.loadmessages": "加载更多信息",
"pad.chat.stick.title": "在屏幕上固定聊天界面",
"pad.chat.writeMessage.placeholder": "在此写下您的消息",
"timeslider.followContents": "跟随记事本的内容更新",
"pad.chat.writeMessage.placeholder": "在这里写下您的留言",
"timeslider.followContents": "关注记事本内容更新",
"timeslider.pageTitle": "{{appTitle}} 时间轴",
"timeslider.toolbar.returnbutton": "返回记事本",
"timeslider.toolbar.authors": "作者:",
@ -150,11 +151,11 @@
"timeslider.toolbar.exportlink.title": "导出",
"timeslider.exportCurrent": "当前版本导出为:",
"timeslider.version": "版本 {{version}}",
"timeslider.saved": "在{{year}}年{{month}}{{day}}日保存",
"timeslider.playPause": "回放 / 暂停Pad内容",
"timeslider.backRevision": "返回此Pad的一次修订",
"timeslider.forwardRevision": "前往此Pad的一次修订",
"timeslider.dateformat": "{{year}}年{{month}}月{{day}}日 {{hours}}:{{minutes}}:{{seconds}}",
"timeslider.saved": "在{{月}}{{日}}{{年}}保存",
"timeslider.playPause": "回放 / 暂停记事本内容",
"timeslider.backRevision": "返回此记事本的一次修订",
"timeslider.forwardRevision": "前往此记事本的下一次修订",
"timeslider.dateformat": "{{月}}/{{日}}/{{年}} {{小时}}{{分钟}}{{秒}}",
"timeslider.month.january": "1月",
"timeslider.month.february": "2月",
"timeslider.month.march": "3月",
@ -167,13 +168,13 @@
"timeslider.month.october": "10月",
"timeslider.month.november": "11月",
"timeslider.month.december": "12月",
"timeslider.unnamedauthors": "{{num}}个匿名作者",
"timeslider.unnamedauthors": "{{num}} 未命名 {[plural(num) one: author, other: authors ]}",
"pad.savedrevs.marked": "这一修订现在被标记为已保存的修订版本",
"pad.savedrevs.timeslider": "您可以使用时间轴查阅已保存的版本",
"pad.userlist.entername": "输入您的姓名",
"pad.userlist.unnamed": "匿名",
"pad.editbar.clearcolors": "清除整个文档的作者颜色吗?此操作无法撤消",
"pad.impexp.importbutton": "现在导入",
"pad.userlist.unnamed": "未命名的",
"pad.editbar.clearcolors": "清除整个文档的作者颜色?这不能被撤消",
"pad.impexp.importbutton": "立即导入",
"pad.impexp.importing": "正在导入...",
"pad.impexp.confirmimport": "导入的文件将覆盖记事本的当前文本。你确定要继续吗?",
"pad.impexp.convertFailed": "我们无法导入此文档。请使用其他文档格式或手动复制贴上。",

View file

@ -1,6 +1,7 @@
{
"@metadata": {
"authors": [
"HellojoeAoPS",
"Justincheng12345",
"Kly",
"LNDDYL",
@ -14,8 +15,8 @@
]
},
"admin.page-title": "管理員面板 - Etherpad",
"admin_plugins": "套件管理",
"admin_plugins.available": "可用套件",
"admin_plugins": "外掛程式管理器",
"admin_plugins.available": "可用套件",
"admin_plugins.available_not-found": "沒有找到套件。",
"admin_plugins.available_fetching": "正在取得…",
"admin_plugins.available_install.value": "安裝",
@ -38,11 +39,11 @@
"admin_plugins_info.page-title": "套件資訊 - Etherpad",
"admin_plugins_info.version": "Etherpad 版本",
"admin_plugins_info.version_latest": "最新可用版本",
"admin_plugins_info.version_number": "版本號",
"admin_plugins_info.version_number": "版本號",
"admin_settings": "設定",
"admin_settings.current": "目前置",
"admin_settings.current": "目前置",
"admin_settings.current_example-devel": "範例開發設定模板",
"admin_settings.current_example-prod": "範例生產設定模板",
"admin_settings.current_example-prod": "生產設定模板範例",
"admin_settings.current_restart.value": "重新啟動 Etherpad",
"admin_settings.current_save.value": "儲存設定",
"admin_settings.page-title": "設定 - Etherpad",
@ -56,11 +57,11 @@
"pad.toolbar.ol.title": "有序清單Ctrl+Shift+N",
"pad.toolbar.ul.title": "無序清單Ctrl+Shift+L",
"pad.toolbar.indent.title": "縮排TAB",
"pad.toolbar.unindent.title": "縮排Shift+TAB",
"pad.toolbar.unindent.title": "減少縮排Shift+TAB",
"pad.toolbar.undo.title": "復原Ctrl+Z",
"pad.toolbar.redo.title": "重做 (Ctrl+Y)",
"pad.toolbar.clearAuthorship.title": "清除作者顏色區別 (Ctrl+Shift+C)",
"pad.toolbar.import_export.title": "以其他檔案格式匯入/匯出",
"pad.toolbar.clearAuthorship.title": "清除作者顏色 (Ctrl+Shift+C)",
"pad.toolbar.import_export.title": "從不同的檔案格式匯入/匯出",
"pad.toolbar.timeslider.title": "時間軸",
"pad.toolbar.savedRevision.title": "儲存修訂版",
"pad.toolbar.settings.title": "設定",
@ -69,22 +70,22 @@
"pad.colorpicker.save": "儲存",
"pad.colorpicker.cancel": "取消",
"pad.loading": "載入中...",
"pad.noCookie": "找不到 Cookie。請允許瀏覽器使用 Cookie您的 session 與設定沒有在訪問期間被儲存下來,這可能是因為在某些瀏覽器裡 Etherpad 被包在 iFrame 中,請確認 Etherpad 是在父層級的 iFrame 相同的網域/子網域。",
"pad.noCookie": "無法找到 Cookie。請在您的瀏覽器中允許cookie您的 session 和設定未在訪問期間保存下來。這可能是由於 Etherpad 包含在某些瀏覽器的 iFrame 中。請確保 Etherpad 與父層級 iFrame 位於同一子網域/網域中",
"pad.permissionDenied": "你沒有存取這個記事本的權限",
"pad.settings.padSettings": "記事本設定",
"pad.settings.myView": "我的視窗",
"pad.settings.stickychat": "永遠在螢幕上顯示聊天",
"pad.settings.chatandusers": "顯示聊天使用者",
"pad.settings.colorcheck": "作者顏色",
"pad.settings.chatandusers": "顯示聊天使用者",
"pad.settings.colorcheck": "作者顏色",
"pad.settings.linenocheck": "行號",
"pad.settings.rtlcheck": "從右至左讀取內容?",
"pad.settings.fontType": "字型類型:",
"pad.settings.fontType.normal": "正常",
"pad.settings.language": "語言:",
"pad.settings.about": "關於",
"pad.settings.poweredBy": "技術提供來自",
"pad.importExport.import_export": "匯入/匯出",
"pad.importExport.import": "上載任何文字檔或文件",
"pad.settings.poweredBy": "技術支援來自",
"pad.importExport.import_export": "導入/匯出",
"pad.importExport.import": "上傳任何文字檔案或文件",
"pad.importExport.importSuccessful": "完成!",
"pad.importExport.export": "匯出目前的記事本為:",
"pad.importExport.exportetherpad": "Etherpad",
@ -93,17 +94,17 @@
"pad.importExport.exportword": "Microsoft Word",
"pad.importExport.exportpdf": "PDF",
"pad.importExport.exportopen": "ODF開放文件格式",
"pad.importExport.abiword.innerHTML": "您只可以從純文字或 HTML 格式檔匯入。<a href=\"ttps://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with-AbiWord\">安裝\n AbiWord 或是 LibreOffice</a> 以取得更多進階的匯入功能。",
"pad.importExport.abiword.innerHTML": "您只可以匯入純文字或HTML格式。若要取得更進階的導入功能請<a href=\"https://github.com/ether/etherpad-lite/wiki/How-to-enable-importing-and-exporting-different-file-formats-with- AbiWord\">安裝AbiWord 或是LibreOffice</a>。",
"pad.modals.connected": "已連線。",
"pad.modals.reconnecting": "重新連線到您的記事本…",
"pad.modals.forcereconnect": "強制重新連線",
"pad.modals.reconnecttimer": "下一次重新連線會在",
"pad.modals.reconnecttimer": "嘗試重新連接",
"pad.modals.cancel": "取消",
"pad.modals.userdup": "在另一個視窗中開啟",
"pad.modals.userdup.explanation": "此記事本似乎在此電腦上的多個瀏覽器視窗中開啟。",
"pad.modals.userdup.advice": "重新連線,並改用這個視窗。",
"pad.modals.userdup.advice": "重新連線以使用此視窗替代。",
"pad.modals.unauth": "未授權",
"pad.modals.unauth.explanation": "您的權限在變更此頁時變更了。請嘗試重新連線。",
"pad.modals.unauth.explanation": "您的權限在查看此頁面時已改變。嘗試重新連線。",
"pad.modals.looping.explanation": "與同步伺服器間有通訊問題。",
"pad.modals.looping.cause": "也許您是透過不相容的防火牆或代理伺服器連線。",
"pad.modals.initsocketfail": "無法存取伺服器。",
@ -111,18 +112,18 @@
"pad.modals.initsocketfail.cause": "這可能是因為瀏覽器或網際網路連線問題所造成。",
"pad.modals.slowcommit.explanation": "伺服器沒有回應。",
"pad.modals.slowcommit.cause": "這可能是因為網路連線問題所造成。",
"pad.modals.badChangeset.explanation": "您的一個編輯被同步伺服器類為非法。",
"pad.modals.badChangeset.cause": "這可能由於伺服器的配置錯誤或遇到意外問題。若您認為這是錯誤,請聯繫伺服器管理員。如要繼續編輯,請嘗試重新連接。",
"pad.modals.badChangeset.explanation": "您所做的一個編輯被同步伺服器類為非法。",
"pad.modals.badChangeset.cause": "這可能是由於伺服器配置錯誤或其他一些意外行為造成的。如果您認為這是一個錯誤,請聯絡服務管理員。嘗試重新連線以繼續編輯。",
"pad.modals.corruptPad.explanation": "您試圖存取的記事本已損壞。",
"pad.modals.corruptPad.cause": "這可能由於伺服器的配置錯誤或遇到意外問題。請聯繫伺服器管理員。",
"pad.modals.corruptPad.cause": "這可能是由於伺服器配置錯誤或其他一些意外行為造成的。請聯絡服務管理員。",
"pad.modals.deleted": "已刪除。",
"pad.modals.deleted.explanation": "此記事本已被移除。",
"pad.modals.rateLimited": "比例限制。",
"pad.modals.rateLimited": "速率限制。",
"pad.modals.rateLimited.explanation": "您發送太多訊息到此記事本,因此中斷了您的連結。",
"pad.modals.rejected.explanation": "伺服器拒絕了由您的瀏覽器發送的訊息。",
"pad.modals.rejected.cause": "當您在檢視記事本時伺服器可能正在更新,或是在 Etherpad 裡有臭蟲。請嘗試重新載入頁面。",
"pad.modals.rejected.cause": "伺服器可能在你查看記事本時更新了也可能是Etherpad出現了錯誤。請嘗試重新載入頁面。",
"pad.modals.disconnected": "您已中斷連線。",
"pad.modals.disconnected.explanation": "伺服器連接曾中斷",
"pad.modals.disconnected.explanation": "與伺服器的連線遺失",
"pad.modals.disconnected.cause": "伺服器可能無法使用。若此情況持續發生,請通知伺服器管理員。",
"pad.share": "分享此記事本",
"pad.share.readonly": "唯讀",
@ -131,20 +132,20 @@
"pad.chat": "聊天功能",
"pad.chat.title": "打開記事本聊天功能",
"pad.chat.loadmessages": "載入更多訊息",
"pad.chat.stick.title": "釘住聊天在螢幕上",
"pad.chat.writeMessage.placeholder": "在此編寫您的訊息",
"pad.chat.stick.title": "在螢幕上固定聊天介面",
"pad.chat.writeMessage.placeholder": "在這裡寫下您的留言",
"timeslider.followContents": "關注記事本內容更新",
"timeslider.pageTitle": "{{appTitle}}時間軸",
"timeslider.toolbar.returnbutton": "返回記事本",
"timeslider.toolbar.authors": "作者:",
"timeslider.toolbar.authorsList": "無作者",
"timeslider.toolbar.authors": "作者:",
"timeslider.toolbar.authorsList": "無作者",
"timeslider.toolbar.exportlink.title": "匯出",
"timeslider.exportCurrent": "匯出當前版本為:",
"timeslider.version": "版本{{version}}",
"timeslider.saved": "{{year}}年{{month}}{{day}}日儲存",
"timeslider.playPause": "放送 / 暫停記事本內容",
"timeslider.saved": "儲存於 {{year}} {{month}} {{day}}",
"timeslider.playPause": "重播 / 暫停記事本內容",
"timeslider.backRevision": "返回此記事本的前一次修訂",
"timeslider.forwardRevision": "前往此記事本的一次修訂",
"timeslider.forwardRevision": "前往此記事本的一次修訂",
"timeslider.dateformat": "{{year}}年{{month}}月{{day}}日 {{hours}}:{{minutes}}:{{seconds}}",
"timeslider.month.january": "1月",
"timeslider.month.february": "2月",
@ -158,20 +159,20 @@
"timeslider.month.october": "10月",
"timeslider.month.november": "11月",
"timeslider.month.december": "12月",
"timeslider.unnamedauthors": "{{num}} 個匿名{[plural(num) one:作者, other:作者]}",
"timeslider.unnamedauthors": "{{num}} 個匿名{[plural(num) one: author, other: authors]}",
"pad.savedrevs.marked": "標記此修訂版本為已儲存修訂版本。",
"pad.savedrevs.timeslider": "您可使用時段滑標來查看先前保存的版本內容",
"pad.savedrevs.timeslider": "您可以透過造訪時間滑桿查看已儲存的修訂",
"pad.userlist.entername": "輸入您的姓名",
"pad.userlist.unnamed": "未命名",
"pad.editbar.clearcolors": "清除整個文檔的協作者顏色區別嗎?此操作無法還原",
"pad.editbar.clearcolors": "清除整個文件的作者顏色?這不能被撤銷",
"pad.impexp.importbutton": "現在匯入",
"pad.impexp.importing": "匯入中...",
"pad.impexp.confirmimport": "匯入的檔案將會覆蓋記事本內目前的文字。您確定要繼續嗎?",
"pad.impexp.convertFailed": "未能匯入此檔案。請以其他檔案格式或手動複製貼上匯入。",
"pad.impexp.padHasData": "此記事本已異動過所以無法匯入該檔案,請匯入至另一個記事本試試。",
"pad.impexp.padHasData": "因為此記事本已異動過我們無法匯入此檔案,請匯入至新的記事本",
"pad.impexp.uploadFailed": "上載失敗,請重試",
"pad.impexp.importfailed": "匯入失敗",
"pad.impexp.copypaste": "請複製貼上",
"pad.impexp.exportdisabled": "{{type}}格式的匯出被禁用。有關詳情,請與您的系統管理員聯繫。",
"pad.impexp.maxFileSize": "檔案太大。請聯絡您的網站管理員來增加用於匯入的允許檔案大小。"
"pad.impexp.maxFileSize": "檔案太大。請聯絡您的網站管理員以增加允許匯入的檔案大小"
}

View file

@ -76,6 +76,7 @@ exports.require = (name, args, mod) => {
basedir = path.dirname(mod.filename);
paths = mod.paths;
}
paths.push(settings.root + '/plugin_packages')
const ejspath = resolve.sync(name, {paths, basedir, extensions: ['.html', '.ejs']});

View file

@ -114,7 +114,7 @@ const doImport = async (req, res, padId, authorId) => {
// ensure this is a file ending we know, else we change the file ending to .txt
// this allows us to accept source code files like .c or .java
const fileEnding = path.extname(srcFile).toLowerCase();
const fileEnding = path.extname(files.file[0].originalFilename).toLowerCase();
const knownFileEndings =
['.txt', '.doc', '.docx', '.pdf', '.odt', '.html', '.htm', '.etherpad', '.rtf'];
const fileEndingUnknown = (knownFileEndings.indexOf(fileEnding) < 0);

View file

@ -43,6 +43,16 @@ exports.expressPreSession = async (hookName, {app}) => {
app.get('/favicon.ico', (req, res, next) => {
(async () => {
/*
If this is a url we simply redirect to that one.
*/
if (settings.favicon && settings.favicon.startsWith('http')) {
res.redirect(settings.favicon);
res.send();
return;
}
const fns = [
...(settings.favicon ? [path.resolve(settings.root, settings.favicon)] : []),
path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'favicon.ico'),

View file

@ -74,6 +74,24 @@ const getAllLocales = () => {
if (typeof overrides !== 'object') throw wrongFormatErr;
_.each(overrides, (localeString, key) => {
if (typeof localeString !== 'string') throw wrongFormatErr;
const locale = locales[langcode];
// Handles the error if an unknown language code is entered
if (locale === undefined) {
const possibleMatches = [];
let strippedLangcode = '';
if (langcode.includes('-')) {
strippedLangcode = langcode.split('-')[0];
}
for (const localeInEtherPad of Object.keys(locales)) {
if (localeInEtherPad.includes(strippedLangcode)) {
possibleMatches.push(localeInEtherPad);
}
}
throw new Error(`Language code ${langcode} is unknown. ` +
`Maybe you meant: ${possibleMatches}`);
}
locales[langcode][key] = localeString;
});
});

View file

@ -49,6 +49,7 @@ const express = require('./hooks/express');
const hooks = require('../static/js/pluginfw/hooks');
const pluginDefs = require('../static/js/pluginfw/plugin_defs');
const plugins = require('../static/js/pluginfw/plugins');
const installer = require('../static/js/pluginfw/installer');
const {Gate} = require('./utils/promises');
const stats = require('./stats');
@ -139,6 +140,7 @@ exports.start = async () => {
}
await db.init();
await installer.checkForMigration();
await plugins.update();
const installedPlugins = Object.values(pluginDefs.plugins)
.filter((plugin) => plugin.package.name !== 'ep_etherpad-lite')

377
src/package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "ep_etherpad-lite",
"version": "1.9.6",
"version": "1.9.7",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -170,9 +170,9 @@
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"@jridgewell/trace-mapping": {
"version": "0.3.20",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
"integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
"version": "0.3.21",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.21.tgz",
"integrity": "sha512-SRfKmRe1KvYnxjEMtxEr+J4HIeMX5YBg/qhRHpxEIGjhX1rshcHlnFUE9K0GazhVKWM7B+nARSkV8LuvJdJ5/g==",
"requires": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@ -261,6 +261,22 @@
"integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==",
"dev": true
},
"@types/debug": {
"version": "4.1.12",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
"integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==",
"requires": {
"@types/ms": "*"
}
},
"@types/fs-extra": {
"version": "9.0.13",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.13.tgz",
"integrity": "sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==",
"requires": {
"@types/node": "*"
}
},
"@types/hast": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.1.tgz",
@ -280,15 +296,20 @@
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
"dev": true
},
"@types/lockfile": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@types/lockfile/-/lockfile-1.0.4.tgz",
"integrity": "sha512-Q8oFIHJHr+htLrTXN2FuZfg+WXVHQRwU/hC2GpUu+Q8e3FUM9EDkS2pE3R2AO1ZGu56f479ybdMCNF1DAu8cAQ=="
},
"@types/lodash": {
"version": "4.14.199",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.199.tgz",
"integrity": "sha512-Vrjz5N5Ia4SEzWWgIVwnHNEnb1UE1XMkvY5DGXrAeOGE9imk0hgTHh5GyDjLDJi9OTCn9oo9dXH1uToK1VRfrg=="
"version": "4.14.202",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz",
"integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ=="
},
"@types/lodash.clonedeep": {
"version": "4.5.7",
"resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.7.tgz",
"integrity": "sha512-ccNqkPptFIXrpVqUECi60/DFxjNKsfoQxSQsgcBJCX/fuX1wgyQieojkcWH/KpE3xzLoWN/2k+ZeGqIN3paSvw==",
"version": "4.5.9",
"resolved": "https://registry.npmjs.org/@types/lodash.clonedeep/-/lodash.clonedeep-4.5.9.tgz",
"integrity": "sha512-19429mWC+FyaAhOLzsS8kZUsI+/GmBAQ0HFiCPsKGU+7pBXOQWhyrY6xNNDwUSX8SMZMJvuFVMF9O5dQOlQK9Q==",
"requires": {
"@types/lodash": "*"
}
@ -301,17 +322,52 @@
"@types/unist": "*"
}
},
"@types/ms": {
"version": "0.7.34",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
},
"@types/node": {
"version": "20.10.6",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz",
"integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==",
"requires": {
"undici-types": "~5.26.4"
}
},
"@types/node-fetch": {
"version": "2.6.10",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.10.tgz",
"integrity": "sha512-PPpPK6F9ALFTn59Ka3BaL+qGuipRfxNE8qVgkp0bVixeiR2c2/L+IVOiBdu9JhhT22sWnQEp6YyHGI2b2+CMcA==",
"requires": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"@types/semver": {
"version": "7.5.3",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz",
"integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==",
"dev": true
"integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw=="
},
"@types/tar": {
"version": "6.1.10",
"resolved": "https://registry.npmjs.org/@types/tar/-/tar-6.1.10.tgz",
"integrity": "sha512-60ZO+W0tRKJ3ggdzJKp75xKVlNogKYMqGvr2bMH/+k3T0BagfYTnbmVDFMJB1BFttz6yRgP5MDGP27eh7brrqw==",
"requires": {
"@types/node": "*",
"minipass": "^4.0.0"
}
},
"@types/unist": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.0.tgz",
"integrity": "sha512-MFETx3tbTjE7Uk6vvnWINA/1iJ7LuMdO4fcq8UfF0pRbj01aGLduVvQcRyswuACJdpnHgg8E3rQLhaRdNEJS0w=="
},
"@types/url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-wDXw9LEEUHyV+7UWy7U315nrJGJ7p1BzaCxDpEoLr789Dk1WDVMMlf3iBfbG2F8NdWnYyFbtTxUn2ZNbm1Q4LQ=="
},
"@typescript-eslint/eslint-plugin": {
"version": "5.62.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz",
@ -575,11 +631,6 @@
"integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==",
"dev": true
},
"ansi-regex": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="
},
"ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
@ -716,11 +767,11 @@
"dev": true
},
"axios": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz",
"integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==",
"version": "1.6.7",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz",
"integrity": "sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==",
"requires": {
"follow-redirects": "^1.15.0",
"follow-redirects": "^1.15.4",
"form-data": "^4.0.0",
"proxy-from-env": "^1.1.0"
}
@ -903,6 +954,11 @@
}
}
},
"chownr": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
"integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="
},
"clean-css": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.3.tgz",
@ -1027,9 +1083,9 @@
}
},
"cssstyle": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-3.0.0.tgz",
"integrity": "sha512-N4u2ABATi3Qplzf0hWbVCdjenim8F3ojEXpBDF5hBpjzW182MjNGLqfmQ0SkSPeQ+V86ZXgeH8aXj6kayd4jgg==",
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
"integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==",
"requires": {
"rrweb-cssom": "^0.6.0"
}
@ -2105,9 +2161,9 @@
"integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ=="
},
"follow-redirects": {
"version": "1.15.3",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz",
"integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q=="
"version": "1.15.5",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz",
"integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw=="
},
"for-each": {
"version": "0.3.3",
@ -2165,6 +2221,24 @@
}
}
},
"fs-minipass": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
"integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==",
"requires": {
"minipass": "^3.0.0"
},
"dependencies": {
"minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"requires": {
"yallist": "^4.0.0"
}
}
}
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@ -2889,11 +2963,11 @@
}
},
"jsdom": {
"version": "23.0.1",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-23.0.1.tgz",
"integrity": "sha512-2i27vgvlUsGEBO9+/kJQRbtqtm+191b5zAZrU/UezVmnC2dlDAFLgDYJvAEi94T4kjsRKkezEtLQTgsNEsW2lQ==",
"version": "24.0.0",
"resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.0.0.tgz",
"integrity": "sha512-UDS2NayCvmXSXVP6mpTj+73JnNQadZlr9N68189xib2tx5Mls7swlTNao26IoHv46BZJFvXygyRtyXd1feAk1A==",
"requires": {
"cssstyle": "^3.0.0",
"cssstyle": "^4.0.1",
"data-urls": "^5.0.0",
"decimal.js": "^10.4.3",
"form-data": "^4.0.0",
@ -2912,8 +2986,15 @@
"whatwg-encoding": "^3.1.1",
"whatwg-mimetype": "^4.0.0",
"whatwg-url": "^14.0.0",
"ws": "^8.14.2",
"ws": "^8.16.0",
"xml-name-validator": "^5.0.0"
},
"dependencies": {
"ws": {
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ=="
}
}
},
"json-buffer": {
@ -3024,6 +3105,66 @@
"immediate": "~3.0.5"
}
},
"live-plugin-manager": {
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/live-plugin-manager/-/live-plugin-manager-0.18.1.tgz",
"integrity": "sha512-GvLMSaZ1Cc18o91NiHLRuPXm1z7xDiUXUGgQ6jAwGM/x0FY8vXXHa/+LMNb2zrkAV2bWULCs0FEwX9yRsmFZmw==",
"requires": {
"@types/debug": "^4.1.7",
"@types/fs-extra": "^9.0.13",
"@types/lockfile": "^1.0.2",
"@types/node-fetch": "^2.5.12",
"@types/semver": "^7.3.9",
"@types/tar": "^6.1.1",
"@types/url-join": "4.0.1",
"debug": "^4.3.3",
"fs-extra": "^10.0.0",
"lockfile": "^1.0.4",
"node-fetch": "^2.6.6",
"semver": "^7.3.5",
"tar": "^6.1.11",
"url-join": "^4.0.1"
},
"dependencies": {
"debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"requires": {
"ms": "2.1.2"
}
},
"fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="
}
}
},
"locate-path": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@ -3033,6 +3174,14 @@
"p-locate": "^5.0.0"
}
},
"lockfile": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz",
"integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==",
"requires": {
"signal-exit": "^3.0.2"
}
},
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
@ -3231,6 +3380,35 @@
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true
},
"minipass": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
"integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="
},
"minizlib": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz",
"integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==",
"requires": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
},
"dependencies": {
"minipass": {
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz",
"integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==",
"requires": {
"yallist": "^4.0.0"
}
}
}
},
"mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
},
"mocha": {
"version": "10.2.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz",
@ -3444,6 +3622,35 @@
}
}
},
"node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"requires": {
"whatwg-url": "^5.0.0"
},
"dependencies": {
"tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"requires": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}
}
},
"nodeify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/nodeify/-/nodeify-1.0.1.tgz",
@ -3631,6 +3838,10 @@
"string-width": "^2.0.0"
}
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true
},
"ansi-styles": {
"version": "3.2.1",
"bundled": true,
@ -3880,8 +4091,7 @@
"dependencies": {
"ansi-regex": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
"bundled": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
@ -6182,6 +6392,10 @@
"strip-ansi": "^4.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"bundled": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"bundled": true
@ -6217,13 +6431,6 @@
"bundled": true,
"requires": {
"ansi-regex": "^2.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA=="
}
}
},
"strip-eof": {
@ -6543,8 +6750,7 @@
"dependencies": {
"ansi-regex": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
"bundled": true
},
"is-fullwidth-code-point": {
"version": "2.0.0",
@ -6615,9 +6821,8 @@
},
"dependencies": {
"ansi-regex": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz",
"integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
"version": "4.1.0",
"bundled": true
},
"find-up": {
"version": "3.0.0",
@ -6779,9 +6984,9 @@
}
},
"openapi-backend": {
"version": "5.10.5",
"resolved": "https://registry.npmjs.org/openapi-backend/-/openapi-backend-5.10.5.tgz",
"integrity": "sha512-ivZfL0Lwj7rRctCqxAquGy4j/VcdUXUvDsEVM3NG/2jDuvYT2dS+sf9ntGo5vv4hkOnkWgPnR6HxHp7NPexqAA==",
"version": "5.10.6",
"resolved": "https://registry.npmjs.org/openapi-backend/-/openapi-backend-5.10.6.tgz",
"integrity": "sha512-vTjBRys/O4JIHdlRHUKZ7pxS+gwIJreAAU9dvYRFrImtPzQ5qxm5a6B8BTVT9m6I8RGGsShJv35MAc3Tu2/y/A==",
"requires": {
"@apidevtools/json-schema-ref-parser": "^11.1.0",
"ajv": "^8.6.2",
@ -7038,9 +7243,9 @@
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
},
"rate-limiter-flexible": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-4.0.0.tgz",
"integrity": "sha512-SkA18LEPqJJKHixi6E7tzBKTXbj9gu5wPyfTykPVRZR5JGSw0dMCjtZsjlfuabVY940pu28Wu87NZN4FhztnyQ=="
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/rate-limiter-flexible/-/rate-limiter-flexible-4.0.1.tgz",
"integrity": "sha512-2/dGHpDFpeA0+755oUkW+EKyklqLS9lu0go9pDsbhqQjZcxfRyJ6LA4JI0+HAdZ2bemD/oOjUeZQB2lCZqXQfQ=="
},
"raw-body": {
"version": "2.5.1",
@ -7272,9 +7477,9 @@
"integrity": "sha512-5qfoAgfRWS1sUn+fUJtdbbqM1BD/LoQGa+smPTDjf9OqHyuJqi6ewtbYL0+V1S1RaU6OCOCMWGZocIfz2YK4uw=="
},
"selenium-webdriver": {
"version": "4.16.0",
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.16.0.tgz",
"integrity": "sha512-IbqpRpfGE7JDGgXHJeWuCqT/tUqnLvZ14csSwt+S8o4nJo3RtQoE9VR4jB47tP/A8ArkYsh/THuMY6kyRP6kuA==",
"version": "4.17.0",
"resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.17.0.tgz",
"integrity": "sha512-e2E+2XBlGepzwgFbyQfSwo9Cbj6G5fFfs9MzAS00nC99EewmcS2rwn2MwtgfP7I5p1e7DYv4HQJXtWedsu6DvA==",
"dev": true,
"requires": {
"jszip": "^3.10.1",
@ -7388,6 +7593,11 @@
"object-inspect": "^1.9.0"
}
},
"signal-exit": {
"version": "3.0.7",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="
},
"sinon": {
"version": "17.0.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz",
@ -7730,13 +7940,13 @@
}
},
"supertest": {
"version": "6.3.3",
"resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.3.tgz",
"integrity": "sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==",
"version": "6.3.4",
"resolved": "https://registry.npmjs.org/supertest/-/supertest-6.3.4.tgz",
"integrity": "sha512-erY3HFDG0dPnhw4U+udPfrzXa4xhSG+n4rxfRuZWCUvjFWwKl+OxWf/7zk50s84/fAAs7vf5QAb9uRa0cCykxw==",
"dev": true,
"requires": {
"methods": "^1.1.2",
"superagent": "^8.0.5"
"superagent": "^8.1.2"
}
},
"supports-color": {
@ -7769,10 +7979,30 @@
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true
},
"tar": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz",
"integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==",
"requires": {
"chownr": "^2.0.0",
"fs-minipass": "^2.0.0",
"minipass": "^5.0.0",
"minizlib": "^2.1.1",
"mkdirp": "^1.0.3",
"yallist": "^4.0.0"
},
"dependencies": {
"minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
"integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="
}
}
},
"terser": {
"version": "5.26.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.26.0.tgz",
"integrity": "sha512-dytTGoE2oHgbNV9nTzgBEPaqAWvcJNl66VZ0BkJqlvp71IjO8CxdBx/ykCNb47cLnCmCvRZ6ZR0tLkqvZCdVBQ==",
"version": "5.27.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.27.0.tgz",
"integrity": "sha512-bi1HRwVRskAjheeYl291n3JC4GgO/Ty4z1nVs5AAsmonJulGxpSektecnNedrwK9C7vpvVtcX3cw00VSLt7U2A==",
"requires": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@ -8002,9 +8232,9 @@
"dev": true
},
"ueberdb2": {
"version": "4.2.44",
"resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-4.2.44.tgz",
"integrity": "sha512-OeVKUtchoRg1O4/sza9PqU1igOfpifqaDyGNuotmG1J6q0uG+0BnUtGNeaOfgoYbDjlI0iPShy792Px6BHr1rw=="
"version": "4.2.50",
"resolved": "https://registry.npmjs.org/ueberdb2/-/ueberdb2-4.2.50.tgz",
"integrity": "sha512-XOiWxmDHhoCNLSrepIJa+kdRBXABuI5ZXQhXpmT2Z8qK3EbipcrAeQBWDQXfcnnHftmzaR3NY7zil76biCN/GQ=="
},
"uid-safe": {
"version": "2.1.5",
@ -8031,6 +8261,11 @@
"resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz",
"integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A=="
},
"undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"unified": {
"version": "11.0.3",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.3.tgz",
@ -8111,6 +8346,11 @@
"punycode": "^2.1.0"
}
},
"url-join": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
},
"url-parse": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
@ -8271,9 +8511,10 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
},
"ws": {
"version": "8.14.2",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz",
"integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g=="
"version": "8.16.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
"integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
"dev": true
},
"wtfnode": {
"version": "0.9.1",

View file

@ -31,7 +31,7 @@
],
"dependencies": {
"async": "^3.2.5",
"axios": "^1.6.2",
"axios": "^1.6.7",
"clean-css": "^5.3.3",
"cookie-parser": "^1.4.6",
"cross-spawn": "^7.0.3",
@ -46,17 +46,18 @@
"formidable": "^3.5.1",
"http-errors": "^2.0.0",
"js-cookie": "^3.0.5",
"jsdom": "^23.0.1",
"jsdom": "^24.0.0",
"jsonminify": "0.4.2",
"languages4translatewiki": "0.1.3",
"live-plugin-manager": "^0.18.1",
"lodash.clonedeep": "4.5.0",
"log4js": "^6.9.1",
"measured-core": "^2.0.0",
"mime-types": "^2.1.35",
"npm": "^6.14.18",
"openapi-backend": "^5.10.5",
"openapi-backend": "^5.10.6",
"proxy-addr": "^2.0.7",
"rate-limiter-flexible": "^4.0.0",
"rate-limiter-flexible": "^4.0.1",
"rehype": "^13.0.1",
"rehype-minify-whitespace": "^6.0.0",
"resolve": "1.22.8",
@ -64,10 +65,10 @@
"semver": "^7.5.4",
"socket.io": "^2.5.0",
"superagent": "^8.1.2",
"terser": "^5.26.0",
"terser": "^5.27.0",
"threads": "^1.7.0",
"tinycon": "0.6.8",
"ueberdb2": "^4.2.44",
"ueberdb2": "^4.2.50",
"underscore": "1.13.6",
"unorm": "1.6.0",
"wtfnode": "^0.9.1"
@ -85,11 +86,11 @@
"mocha-froth": "^0.2.10",
"nodeify": "^1.0.1",
"openapi-schema-validation": "^0.4.2",
"selenium-webdriver": "^4.16.0",
"selenium-webdriver": "^4.17.0",
"set-cookie-parser": "^2.6.0",
"sinon": "^17.0.1",
"split-grid": "^1.0.11",
"supertest": "^6.3.3",
"supertest": "^6.3.4",
"typescript": "^5.3.3"
},
"engines": {
@ -105,6 +106,6 @@
"test": "mocha --timeout 120000 --recursive tests/backend/specs ../node_modules/ep_*/static/tests/backend/specs",
"test-container": "mocha --timeout 5000 tests/container/specs/api"
},
"version": "1.9.6",
"version": "1.9.7",
"license": "Apache-2.0"
}

View file

@ -6,10 +6,19 @@ const hooks = require('./hooks');
const runCmd = require('../../../node/utils/run_cmd');
const settings = require('../../../node/utils/Settings');
const axios = require('axios');
const {PluginManager} = require("live-plugin-manager");
const {promises: fs} = require("fs");
const path = require("path");
const {findEtherpadRoot} = require("../../../node/utils/AbsolutePaths");
const logger = log4js.getLogger('plugins');
exports.manager = new PluginManager();
const installedPluginsPath = path.join(settings.root, 'var/installed_plugins.json');
const onAllTasksFinished = async () => {
await plugins.update();
await persistInstalledPlugins();
settings.reloadSettings();
await hooks.aCallAll('loadSettings', {settings});
await hooks.aCallAll('restartServer');
@ -31,41 +40,74 @@ const wrapTaskCb = (cb) => {
};
};
const migratePluginsFromNodeModules = async () => {
logger.info('start migration of plugins in node_modules')
// Notes:
// * Do not pass `--prod` otherwise `npm ls` will fail if there is no `package.json`.
// * The `--no-production` flag is required (or the `NODE_ENV` environment variable must be
// unset or set to `development`) because otherwise `npm ls` will not mention any packages
// that are not included in `package.json` (which is expected to not exist).
const cmd = ['npm', 'ls', '--long', '--json', '--depth=0', '--no-production'];
const {dependencies = {}} = JSON.parse(await runCmd(cmd, {stdio: [null, 'string']}));
await Promise.all(Object.entries(dependencies).map(async ([pkg, info]) => {
if (pkg.startsWith(plugins.prefix) && pkg !== 'ep_etherpad-lite') {
if (!info._resolved) {
// Install from node_modules directory
await exports.manager.installFromPath(`${findEtherpadRoot()}/node_modules/${pkg}`);
} else {
await exports.manager.install(pkg);
}
}
}));
await persistInstalledPlugins();
};
exports.checkForMigration = async () => {
logger.info('check installed plugins for migration');
try {
await fs.access(installedPluginsPath, fs.constants.F_OK);
} catch (err) {
await migratePluginsFromNodeModules();
}
const fileContent = await fs.readFile(installedPluginsPath);
const installedPlugins = JSON.parse(fileContent.toString());
for (const plugin of installedPlugins.plugins) {
if (plugin.name.startsWith(plugins.prefix) && plugin.name !== 'ep_etherpad-lite') {
await exports.manager.install(plugin.name, plugin.version)
}
}
};
const persistInstalledPlugins = async () => {
let installedPlugins = { plugins: []};
for (const pkg of Object.values(await plugins.getPackages())) {
installedPlugins.plugins.push({
name: pkg.name,
version: pkg.version,
})
}
installedPlugins.plugins = [...new Set(installedPlugins.plugins)];
await fs.writeFile(installedPluginsPath, JSON.stringify(installedPlugins));
}
exports.uninstall = async (pluginName, cb = null) => {
cb = wrapTaskCb(cb);
logger.info(`Uninstalling plugin ${pluginName}...`);
try {
// The --no-save flag prevents npm from creating package.json or package-lock.json.
// The --legacy-peer-deps flag is required to work around a bug in npm v7:
// https://github.com/npm/cli/issues/2199
await runCmd(['npm', 'uninstall', '--no-save', '--legacy-peer-deps', pluginName]);
} catch (err) {
logger.error(`Failed to uninstall plugin ${pluginName}`);
cb(err || new Error(err));
throw err;
}
await exports.manager.uninstall(pluginName);
logger.info(`Successfully uninstalled plugin ${pluginName}`);
await hooks.aCallAll('pluginUninstall', {pluginName});
await plugins.update();
cb(null);
};
exports.install = async (pluginName, cb = null) => {
cb = wrapTaskCb(cb);
logger.info(`Installing plugin ${pluginName}...`);
try {
// The --no-save flag prevents npm from creating package.json or package-lock.json.
// The --legacy-peer-deps flag is required to work around a bug in npm v7:
// https://github.com/npm/cli/issues/2199
await runCmd(['npm', 'install', '--no-save', '--legacy-peer-deps', pluginName]);
} catch (err) {
logger.error(`Failed to install plugin ${pluginName}`);
cb(err || new Error(err));
throw err;
}
await exports.manager.install(pluginName);
logger.info(`Successfully installed plugin ${pluginName}`);
await hooks.aCallAll('pluginInstall', {pluginName});
await plugins.update();
cb(null);
};
@ -76,22 +118,21 @@ exports.getAvailablePlugins = (maxCacheAge) => {
const nowTimestamp = Math.round(Date.now() / 1000);
return new Promise(async (resolve, reject) => {
// check cache age before making any request
if (exports.availablePlugins && maxCacheAge && (nowTimestamp - cacheTimestamp) <= maxCacheAge) {
return resolve(exports.availablePlugins);
}
// check cache age before making any request
if (exports.availablePlugins && maxCacheAge && (nowTimestamp - cacheTimestamp) <= maxCacheAge) {
return resolve(exports.availablePlugins);
}
await axios.get('https://static.etherpad.org/plugins.json', {headers: headers})
.then(pluginsLoaded => {
exports.availablePlugins = pluginsLoaded.data;
cacheTimestamp = nowTimestamp;
resolve(exports.availablePlugins);
})
await axios.get('https://static.etherpad.org/plugins.json', {headers: headers})
.then((pluginsLoaded) => {
exports.availablePlugins = pluginsLoaded.data;
cacheTimestamp = nowTimestamp;
resolve(exports.availablePlugins);})
.catch(async err => {
return reject(err);
});
})
}
});
};
exports.search = (searchTerm, maxCacheAge) => exports.getAvailablePlugins(maxCacheAge).then(
@ -108,8 +149,8 @@ exports.search = (searchTerm, maxCacheAge) => exports.getAvailablePlugins(maxCac
if (pluginName.indexOf(plugins.prefix) !== 0) continue;
if (searchTerm && !~results[pluginName].name.toLowerCase().indexOf(searchTerm) &&
(typeof results[pluginName].description !== 'undefined' &&
!~results[pluginName].description.toLowerCase().indexOf(searchTerm))
(typeof results[pluginName].description !== 'undefined' &&
!~results[pluginName].description.toLowerCase().indexOf(searchTerm))
) {
if (typeof results[pluginName].description === 'undefined') {
logger.debug(`plugin without Description: ${results[pluginName].name}`);

View file

@ -8,6 +8,8 @@ const runCmd = require('../../../node/utils/run_cmd');
const tsort = require('./tsort');
const pluginUtils = require('./shared');
const defs = require('./plugin_defs');
const {manager} = require('./installer');
const settings = require("../../../node/utils/Settings");
const logger = log4js.getLogger('plugins');
@ -105,22 +107,26 @@ exports.update = async () => {
};
exports.getPackages = async () => {
logger.info('Running npm to get a list of installed plugins...');
// Notes:
// * Do not pass `--prod` otherwise `npm ls` will fail if there is no `package.json`.
// * The `--no-production` flag is required (or the `NODE_ENV` environment variable must be
// unset or set to `development`) because otherwise `npm ls` will not mention any packages
// that are not included in `package.json` (which is expected to not exist).
const cmd = ['npm', 'ls', '--long', '--json', '--depth=0', '--no-production'];
const {dependencies = {}} = JSON.parse(await runCmd(cmd, {stdio: [null, 'string']}));
await Promise.all(Object.entries(dependencies).map(async ([pkg, info]) => {
if (!pkg.startsWith(exports.prefix)) {
delete dependencies[pkg];
return;
let plugins = manager.list()
let newDependencies = {}
for (const plugin of plugins) {
if (!plugin.name.startsWith(exports.prefix)) {
continue;
}
info.realPath = await fs.realpath(info.path);
}));
return dependencies;
plugin.realPath = await fs.realpath(plugin.location);
plugin.path = plugin.realPath;
newDependencies[plugin.name] = plugin
}
newDependencies['ep_etherpad-lite'] = {
name: 'ep_etherpad-lite',
version: settings.getEpVersion(),
path: path.join(settings.root, 'node_modules/ep_etherpad-lite'),
realPath: path.join(settings.root, 'src'),
}
return newDependencies;
};
const loadPlugin = async (packages, pluginName, plugins, parts) => {

View file

@ -51,6 +51,12 @@ describe(__filename, function () {
assert(gotIcon.equals(wantCustomIcon));
});
it('uses custom favicon from url', async function () {
settings.favicon = 'https://etherpad.org/favicon.ico';
await agent.get('/favicon.ico')
.expect(302);
});
it('uses custom favicon if set (absolute pathname)', async function () {
settings.favicon = path.join(__dirname, 'favicon-test-custom.png');
assert(path.isAbsolute(settings.favicon));

1
var/.gitignore vendored
View file

@ -1,2 +1,3 @@
sqlite.db
minified*
installed_plugins.json