diff --git a/CHANGELOG.md b/CHANGELOG.md index 0481c252c3..d543258906 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,15 @@ --> # Changelog +## 11.0.0-beta.1 + +### Fixed +- Make preview timeout an info log instead of error by @CarlSchwan in [#5613](https://github.com/nextcloud/richdocuments/pull/5613) + +### Other +- Temporarily revert pdf viewer assertion by @elzody in [#5578](https://github.com/nextcloud/richdocuments/pull/5578) +- Enhance direct editing test with postMessage handling by @elzody in [#5555](https://github.com/nextcloud/richdocuments/pull/5555) + ## 10.0.0-beta.1 ### Added diff --git a/appinfo/info.xml b/appinfo/info.xml index 7fa639d451..826a042ea2 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -11,7 +11,7 @@ - 11.0.0-dev.0 + 12.0.0-dev.0 agpl Collabora Productivity based on work of Frank Karlitschek, Victor Dubiniuk @@ -32,7 +32,7 @@ You can also edit your documents off-line with the Collabora Office app from the https://github.com/nextcloud/richdocuments/raw/main/screenshots/Nextcloud-spreadsheet.png https://github.com/nextcloud/richdocuments/raw/main/screenshots/Nextcloud-presentation.png - + OCA\Richdocuments\Backgroundjobs\ObtainCapabilities @@ -55,4 +55,12 @@ You can also edit your documents off-line with the Collabora Office app from the OCA\Richdocuments\Settings\Personal OCA\Richdocuments\Settings\Section + + + Office + richdocuments.overview.index + app.svg + 10 + + diff --git a/appinfo/routes.php b/appinfo/routes.php index e17267f6ce..6646968513 100644 --- a/appinfo/routes.php +++ b/appinfo/routes.php @@ -24,6 +24,9 @@ // external api access ['name' => 'document#extAppGetData', 'url' => '/ajax/extapp/data/{fileId}', 'verb' => 'POST'], + // Office overview page + ['name' => 'overview#index', 'url' => '/overview', 'verb' => 'GET'], + // Settings ['name' => 'settings#setPersonalSettings', 'url' => 'ajax/personal.php', 'verb' => 'POST'], ['name' => 'settings#setSettings', 'url' => 'ajax/admin.php', 'verb' => 'POST'], diff --git a/composer.lock b/composer.lock index 76d105eebb..49f4fba57b 100644 --- a/composer.lock +++ b/composer.lock @@ -694,16 +694,16 @@ }, { "name": "phpseclib/phpseclib", - "version": "3.0.51", + "version": "3.0.52", "source": { "type": "git", "url": "https://github.com/phpseclib/phpseclib.git", - "reference": "d59c94077f9c9915abb51ddb52ce85188ece1748" + "reference": "2adaefc83df2ec548558307690f376dd7d4f4fce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/d59c94077f9c9915abb51ddb52ce85188ece1748", - "reference": "d59c94077f9c9915abb51ddb52ce85188ece1748", + "url": "https://api.github.com/repos/phpseclib/phpseclib/zipball/2adaefc83df2ec548558307690f376dd7d4f4fce", + "reference": "2adaefc83df2ec548558307690f376dd7d4f4fce", "shasum": "" }, "require": { @@ -784,7 +784,7 @@ ], "support": { "issues": "https://github.com/phpseclib/phpseclib/issues", - "source": "https://github.com/phpseclib/phpseclib/tree/3.0.51" + "source": "https://github.com/phpseclib/phpseclib/tree/3.0.52" }, "funding": [ { @@ -800,7 +800,7 @@ "type": "tidelift" } ], - "time": "2026-04-10T01:33:53+00:00" + "time": "2026-04-27T07:02:15+00:00" }, { "name": "psr/event-dispatcher", @@ -1348,12 +1348,12 @@ "source": { "type": "git", "url": "https://github.com/nextcloud-deps/ocp.git", - "reference": "1e8078631ee2c4da77e39fd7addebd1837889298" + "reference": "f3fddf2af92f48d3f53569074f69f0ae4bad52b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/1e8078631ee2c4da77e39fd7addebd1837889298", - "reference": "1e8078631ee2c4da77e39fd7addebd1837889298", + "url": "https://api.github.com/repos/nextcloud-deps/ocp/zipball/f3fddf2af92f48d3f53569074f69f0ae4bad52b6", + "reference": "f3fddf2af92f48d3f53569074f69f0ae4bad52b6", "shasum": "" }, "require": { @@ -1390,7 +1390,7 @@ "issues": "https://github.com/nextcloud-deps/ocp/issues", "source": "https://github.com/nextcloud-deps/ocp/tree/master" }, - "time": "2026-04-25T01:21:25+00:00" + "time": "2026-05-09T01:52:54+00:00" }, { "name": "nikic/php-parser", diff --git a/cypress/e2e/open.spec.js b/cypress/e2e/open.spec.js index 5167edd5c5..3df730fe61 100644 --- a/cypress/e2e/open.spec.js +++ b/cypress/e2e/open.spec.js @@ -122,9 +122,7 @@ describe('Open PDF with richdocuments', () => { .its('body').should('not.be.empty') .as('pdfViewer') - // TODO: Once fixed upstream, this will start failing again and can be reverted - // https://github.com/nextcloud/files_pdfviewer/pull/1422 - cy.get('@pdfViewer').find('.pdfViewer').should('not.exist') + cy.get('@pdfViewer').find('.pdfViewer').should('exist') }) // Verify that using the file action 'Edit with Nextcloud Office' diff --git a/cypress/e2e/overview.spec.js b/cypress/e2e/overview.spec.js new file mode 100644 index 0000000000..06acc8c840 --- /dev/null +++ b/cypress/e2e/overview.spec.js @@ -0,0 +1,158 @@ +/** + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +const CATEGORY_FILES = [ + { + category: 'Documents', + emptyMessage: 'No documents found', + fixture: 'document.odt', + mimeType: 'application/vnd.oasis.opendocument.text', + }, + { + category: 'Presentations', + emptyMessage: 'No presentations found', + fixture: 'presentation.odp', + mimeType: 'application/vnd.oasis.opendocument.presentation', + }, + { + category: 'Spreadsheets', + emptyMessage: 'No spreadsheets found', + fixture: 'spreadsheet.ods', + mimeType: 'application/vnd.oasis.opendocument.spreadsheet', + }, + { + category: 'Diagrams', + emptyMessage: 'No diagrams found', + fixture: 'drawing.odg', + mimeType: 'application/vnd.oasis.opendocument.graphics', + }, +] + +describe('Office overview page', function() { + describe('without files', function() { + let randUser + + before(function() { + cy.createRandomUser().then(user => { + randUser = user + }) + }) + + beforeEach(function() { + cy.login(randUser) + cy.visit('/apps/richdocuments/overview') + }) + + it('Shows the navigation sidebar with appropriate entries', function() { + CATEGORY_FILES.forEach(({ category }) => { + cy.contains('.app-navigation-entry', category).should('exist') + }) + }) + + it('Highlights the active navigation item and shows empty state on click', function() { + CATEGORY_FILES.forEach(({ category, emptyMessage }) => { + cy.contains('.app-navigation-entry', category).click() + cy.contains('.app-navigation-entry', category) + .should('have.class', 'active') + cy.get('.empty-content') + .should('be.visible') + .and('contain', emptyMessage) + }) + }) + }) + + describe('with files', function() { + let randUser + + before(function() { + cy.createRandomUser().then(user => { + randUser = user + cy.login(user) + + CATEGORY_FILES.forEach(({ fixture, mimeType }) => { + cy.uploadFile(user, fixture, mimeType, `/${fixture}`) + }) + + cy.createFolder(user, 'subfolder').then(() => { + CATEGORY_FILES.forEach(({ fixture, mimeType }) => { + cy.uploadFile(user, fixture, mimeType, `/subfolder/${fixture}`) + }) + }) + }) + }) + + beforeEach(function() { + cy.login(randUser) + cy.visit('/apps/richdocuments/overview', { + onBeforeLoad(win) { + cy.spy(win, 'postMessage').as('postMessage') + }, + }) + }) + + CATEGORY_FILES.forEach(({ category, fixture }) => { + it(`Shows ${category} file cards in the correct category`, function() { + cy.contains('.app-navigation-entry', category).click() + + cy.contains('.file-card__name', fixture) + .should('be.visible') + + cy.get('.file-card__preview img') + .should('exist') + + cy.get('.input-field__label') + .should('contain', `Search ${category.toLowerCase()}`) + }) + + it(`Opens the viewer when clicking a ${category} file card`, function() { + cy.contains('.app-navigation-entry', category).click() + cy.contains('.file-card', fixture).click() + + cy.waitForViewer() + cy.waitForCollabora() + + cy.closeDocument() + }) + }) + + it('Shows file cards for files in subdirectories', function() { + CATEGORY_FILES.forEach(({ category }) => { + cy.contains('.app-navigation-entry', category).click() + cy.get('.file-card').should('have.length.at.least', 2) + }) + }) + + it('Filters file cards by search query', function() { + const { category, fixture } = CATEGORY_FILES[0] + const stem = fixture.split('.')[0] + + cy.contains('.app-navigation-entry', category).click() + + cy.get('.office-overview__search [type="search"]').type(stem) + cy.contains('.file-card__name', fixture).should('be.visible') + }) + + it('Shows empty state when search matches nothing', function() { + const { category } = CATEGORY_FILES[0] + + cy.contains('.app-navigation-entry', category).click() + + cy.get('.office-overview__search [type="search"]').type('xyz123noresults') + cy.get('.empty-content').should('be.visible') + }) + + it('Resets search when switching categories', function() { + const [first, second] = CATEGORY_FILES + + cy.contains('.app-navigation-entry', first.category).click() + cy.get('.office-overview__search [type="search"]').type('xyz123noresults') + + cy.contains('.app-navigation-entry', second.category).click() + + cy.get('.office-overview__search [type="search"]').should('have.value', '') + cy.contains('.file-card__name', second.fixture).should('be.visible') + }) + }) +}) diff --git a/cypress/e2e/settings.spec.js b/cypress/e2e/settings.spec.js index 3b01fdda26..5aff132b20 100644 --- a/cypress/e2e/settings.spec.js +++ b/cypress/e2e/settings.spec.js @@ -20,10 +20,10 @@ describe('Office admin settings', function() { }) it('Error for invalid url', function() { - cy.get('#app-content') + cy.get('#app-content-vue') .scrollTo('topLeft') - cy.get('#app-content') + cy.get('#app-content-vue') .scrollIntoView() .should('be.visible') cy.screenshot() @@ -40,10 +40,10 @@ describe('Office admin settings', function() { }) it('Opens settings and configure a valid url', function() { - cy.get('#app-content') + cy.get('#app-content-vue') .scrollTo('topLeft') - cy.get('#app-content') + cy.get('#app-content-vue') .scrollIntoView() .should('be.visible') cy.screenshot() diff --git a/cypress/e2e/templates.spec.js b/cypress/e2e/templates.spec.js index e8da9e890f..e5187bf2a6 100644 --- a/cypress/e2e/templates.spec.js +++ b/cypress/e2e/templates.spec.js @@ -52,7 +52,7 @@ describe('Global templates', function() { .scrollIntoView() cy.intercept('DELETE', '**/richdocuments/template/*').as('templateDeleteRequest') - cy.get('.template-btn[data-cy-template-btn-name="systemtemplate"]').click() + cy.get('.file-card[data-cy-template-btn-name="systemtemplate"]').click() cy.wait('@templateDeleteRequest').then(({ response }) => { expect(response.statusCode).to.equal(204) diff --git a/emptyTemplates/document.ott b/emptyTemplates/document.ott index a0a5677a0a..b2c859b91e 100644 Binary files a/emptyTemplates/document.ott and b/emptyTemplates/document.ott differ diff --git a/l10n/de.js b/l10n/de.js index a43f7c962f..0f8de42031 100644 --- a/l10n/de.js +++ b/l10n/de.js @@ -83,7 +83,7 @@ OC.L10N.register( "Empty" : "Leer", "Anonymous guest" : "Anonymer Gast", "%s (Guest)" : "%s (Gast)", - "Edit office documents directly in your browser." : "Bearbeite Office-Dokumente direkt in deinem Browser", + "Edit office documents directly in your browser." : "Office-Dokumente direkt im Browser bearbeiten.", "This application can connect to a Collabora Online (or other) server (WOPI-like Client). Nextcloud is the WOPI Host. Please read the documentation to learn more about that.\n\nYou can also edit your documents off-line with the Collabora Office app from the **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** and **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** store." : "Diese App kann sich mit einem Collabora Online (oder anderem) Server (als WOPI-ähnlicher Client) verbinden. Nextcloud ist der WOPI-Host. Weitere Einzelheiten hierzu sind in der Dokumentation zu finden.\n\nDokumente können auch offline mit der Collabora Office App aus dem **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** und **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** Store bearbeitet werden.", "Instance-wide templates that should be available to all users." : "Instanzweite Vorlagen, die allen Benutzern zur Verfügung stehen sollten.", "Uploaded template \"{name}\"" : "Hochgeladene Vorlage \"{name}\"", diff --git a/l10n/de.json b/l10n/de.json index 4794249fde..c86c967b48 100644 --- a/l10n/de.json +++ b/l10n/de.json @@ -81,7 +81,7 @@ "Empty" : "Leer", "Anonymous guest" : "Anonymer Gast", "%s (Guest)" : "%s (Gast)", - "Edit office documents directly in your browser." : "Bearbeite Office-Dokumente direkt in deinem Browser", + "Edit office documents directly in your browser." : "Office-Dokumente direkt im Browser bearbeiten.", "This application can connect to a Collabora Online (or other) server (WOPI-like Client). Nextcloud is the WOPI Host. Please read the documentation to learn more about that.\n\nYou can also edit your documents off-line with the Collabora Office app from the **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** and **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** store." : "Diese App kann sich mit einem Collabora Online (oder anderem) Server (als WOPI-ähnlicher Client) verbinden. Nextcloud ist der WOPI-Host. Weitere Einzelheiten hierzu sind in der Dokumentation zu finden.\n\nDokumente können auch offline mit der Collabora Office App aus dem **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** und **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** Store bearbeitet werden.", "Instance-wide templates that should be available to all users." : "Instanzweite Vorlagen, die allen Benutzern zur Verfügung stehen sollten.", "Uploaded template \"{name}\"" : "Hochgeladene Vorlage \"{name}\"", diff --git a/l10n/de_DE.js b/l10n/de_DE.js index 05133c377f..2b8b643068 100644 --- a/l10n/de_DE.js +++ b/l10n/de_DE.js @@ -83,7 +83,7 @@ OC.L10N.register( "Empty" : "Leer", "Anonymous guest" : "Anonymer Gast", "%s (Guest)" : "%s (Gast)", - "Edit office documents directly in your browser." : "Bearbeiten Sie Office-Dokumente direkt in Ihrem Browser.", + "Edit office documents directly in your browser." : "Office-Dokumente direkt im Browser bearbeiten.", "This application can connect to a Collabora Online (or other) server (WOPI-like Client). Nextcloud is the WOPI Host. Please read the documentation to learn more about that.\n\nYou can also edit your documents off-line with the Collabora Office app from the **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** and **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** store." : "Diese App kann sich mit einem Collabora Online (oder anderem) Server (als WOPI-ähnlicher Client) verbinden. Nextcloud ist der WOPI-Host. Weitere Einzelheiten hierzu sind in der Dokumentation zu finden.\n\nDokumente können auch offline mit der Collabora Office App aus dem **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** und **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** Store bearbeitet werden.", "Instance-wide templates that should be available to all users." : "Instanzweite Vorlagen, die allen Benutzern zur Verfügung stehen sollten.", "Uploaded template \"{name}\"" : "Hochgeladene Vorlage \"{name}\"", diff --git a/l10n/de_DE.json b/l10n/de_DE.json index 7adc33e9ad..29dd4ef43b 100644 --- a/l10n/de_DE.json +++ b/l10n/de_DE.json @@ -81,7 +81,7 @@ "Empty" : "Leer", "Anonymous guest" : "Anonymer Gast", "%s (Guest)" : "%s (Gast)", - "Edit office documents directly in your browser." : "Bearbeiten Sie Office-Dokumente direkt in Ihrem Browser.", + "Edit office documents directly in your browser." : "Office-Dokumente direkt im Browser bearbeiten.", "This application can connect to a Collabora Online (or other) server (WOPI-like Client). Nextcloud is the WOPI Host. Please read the documentation to learn more about that.\n\nYou can also edit your documents off-line with the Collabora Office app from the **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** and **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** store." : "Diese App kann sich mit einem Collabora Online (oder anderem) Server (als WOPI-ähnlicher Client) verbinden. Nextcloud ist der WOPI-Host. Weitere Einzelheiten hierzu sind in der Dokumentation zu finden.\n\nDokumente können auch offline mit der Collabora Office App aus dem **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** und **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** Store bearbeitet werden.", "Instance-wide templates that should be available to all users." : "Instanzweite Vorlagen, die allen Benutzern zur Verfügung stehen sollten.", "Uploaded template \"{name}\"" : "Hochgeladene Vorlage \"{name}\"", diff --git a/l10n/fr.js b/l10n/fr.js index 3b9614b8d7..3954768ee3 100644 --- a/l10n/fr.js +++ b/l10n/fr.js @@ -167,18 +167,18 @@ OC.L10N.register( "Previews will be blocked" : "Les aperçus seront bloqués", "Enable secure view" : "Activer la vue sécurisée", "Supported placeholders: {userId}, {userDisplayName}, {email}, {date}, {themingName}" : "Balises possibles : {userId}, {userDisplayName}, {email}, {date}, {themingName}", - "Enforce secure view on tagged files" : "Appliquer l'affichage sécurisé aux fichiers marqués", + "Enforce secure view on tagged files" : "Forcer l'affichage sécurisé pour les fichiers étiquetés", "Select tags to enforce watermarking" : "Sélectionner des étiquettes pour appliquer le filigrane", - "Enforce secure view for users of groups" : "Appliquer l'affichage sécurisé aux utilisateurs des groupes", - "Enforce secure view for all shares" : "Appliquer l'affichage sécurisé aux partages", - "Enforce secure view for read only shares" : "Appliquer l'affichage sécurisé aux partages en lecture seule", - "Enforce secure view for all public Talk shares" : "Appliquer l'affichage sécurisé aux partages publics Talk", - "Enforce secure view for shares without download permission" : "Appliquer l'affichage sécurisé aux partages sans droit de téléchargement", - "Enforce secure view for all link shares" : "Appliquer l'affichage sécurisé à tous les liens de partage", - "Enforce secure view for download hidden shares" : "Appliquer l'affichage sécurisé aux téléchargements de partages masqués", - "Enforce secure view for read only link shares" : "Appliquer l'affichage sécurisé aux liens de partage en lecture seule", - "Enforce secure view on link shares with specific system tags" : "Appliquer l'affichage sécurisé aux liens de partage avec des étiquettes spécifiques", - "Select tags to enforce secure view" : "Sélectionnez les étiquettes pour appliquer l'affichage sécurisé", + "Enforce secure view for users of groups" : "Forcer l'affichage sécurisé pour les utilisateurs des groupes", + "Enforce secure view for all shares" : "Forcer l'affichage sécurisé pour tous les partages", + "Enforce secure view for read only shares" : "Forcer l'affichage sécurisé pour partages en lecture seule", + "Enforce secure view for all public Talk shares" : "Forcer l'affichage sécurisé pour les partages publics de Talk", + "Enforce secure view for shares without download permission" : "Forcer l'affichage sécurisé pour les partages sans droit de téléchargement", + "Enforce secure view for all link shares" : "Forcer l'affichage sécurisé pour tous les liens de partage", + "Enforce secure view for download hidden shares" : "Forcer l'affichage sécurisé pour les partages avec téléchargement masqué", + "Enforce secure view for read only link shares" : "Forcer l'affichage sécurisé pour les liens de partage en lecture seule", + "Enforce secure view on link shares with specific system tags" : "Forcer l'affichage sécurisé pour les liens de partage avec des étiquettes spécifiques", + "Select tags to enforce secure view" : "Sélectionnez des étiquettes pour forcer l'affichage sécurisé", "Electronic Signature" : "Signature électronique", "Client ID for the electronic signature API" : "Identifiant Client pour l'API de signature électronique", "Fill in the registration form at https://eideasy.com/signup to obtain a client ID and secret." : "Créer un compte sur https://eideasy.com/signup pour obtenir un identifiant client et son secret.", @@ -194,6 +194,7 @@ OC.L10N.register( "Save As" : "Enregistrer sous", "Save as" : "Enregistrer sous", "Path to save" : "Chemin de sauvegarde", + "Checking…" : "Vérification…", "Invalid file name" : "Nom de fichier invalide", "File name already exists" : "Le nom de fichier existe déjà", "Select template" : "Sélectionnez un modèle", diff --git a/l10n/fr.json b/l10n/fr.json index c8c4cea167..9e9436ea79 100644 --- a/l10n/fr.json +++ b/l10n/fr.json @@ -165,18 +165,18 @@ "Previews will be blocked" : "Les aperçus seront bloqués", "Enable secure view" : "Activer la vue sécurisée", "Supported placeholders: {userId}, {userDisplayName}, {email}, {date}, {themingName}" : "Balises possibles : {userId}, {userDisplayName}, {email}, {date}, {themingName}", - "Enforce secure view on tagged files" : "Appliquer l'affichage sécurisé aux fichiers marqués", + "Enforce secure view on tagged files" : "Forcer l'affichage sécurisé pour les fichiers étiquetés", "Select tags to enforce watermarking" : "Sélectionner des étiquettes pour appliquer le filigrane", - "Enforce secure view for users of groups" : "Appliquer l'affichage sécurisé aux utilisateurs des groupes", - "Enforce secure view for all shares" : "Appliquer l'affichage sécurisé aux partages", - "Enforce secure view for read only shares" : "Appliquer l'affichage sécurisé aux partages en lecture seule", - "Enforce secure view for all public Talk shares" : "Appliquer l'affichage sécurisé aux partages publics Talk", - "Enforce secure view for shares without download permission" : "Appliquer l'affichage sécurisé aux partages sans droit de téléchargement", - "Enforce secure view for all link shares" : "Appliquer l'affichage sécurisé à tous les liens de partage", - "Enforce secure view for download hidden shares" : "Appliquer l'affichage sécurisé aux téléchargements de partages masqués", - "Enforce secure view for read only link shares" : "Appliquer l'affichage sécurisé aux liens de partage en lecture seule", - "Enforce secure view on link shares with specific system tags" : "Appliquer l'affichage sécurisé aux liens de partage avec des étiquettes spécifiques", - "Select tags to enforce secure view" : "Sélectionnez les étiquettes pour appliquer l'affichage sécurisé", + "Enforce secure view for users of groups" : "Forcer l'affichage sécurisé pour les utilisateurs des groupes", + "Enforce secure view for all shares" : "Forcer l'affichage sécurisé pour tous les partages", + "Enforce secure view for read only shares" : "Forcer l'affichage sécurisé pour partages en lecture seule", + "Enforce secure view for all public Talk shares" : "Forcer l'affichage sécurisé pour les partages publics de Talk", + "Enforce secure view for shares without download permission" : "Forcer l'affichage sécurisé pour les partages sans droit de téléchargement", + "Enforce secure view for all link shares" : "Forcer l'affichage sécurisé pour tous les liens de partage", + "Enforce secure view for download hidden shares" : "Forcer l'affichage sécurisé pour les partages avec téléchargement masqué", + "Enforce secure view for read only link shares" : "Forcer l'affichage sécurisé pour les liens de partage en lecture seule", + "Enforce secure view on link shares with specific system tags" : "Forcer l'affichage sécurisé pour les liens de partage avec des étiquettes spécifiques", + "Select tags to enforce secure view" : "Sélectionnez des étiquettes pour forcer l'affichage sécurisé", "Electronic Signature" : "Signature électronique", "Client ID for the electronic signature API" : "Identifiant Client pour l'API de signature électronique", "Fill in the registration form at https://eideasy.com/signup to obtain a client ID and secret." : "Créer un compte sur https://eideasy.com/signup pour obtenir un identifiant client et son secret.", @@ -192,6 +192,7 @@ "Save As" : "Enregistrer sous", "Save as" : "Enregistrer sous", "Path to save" : "Chemin de sauvegarde", + "Checking…" : "Vérification…", "Invalid file name" : "Nom de fichier invalide", "File name already exists" : "Le nom de fichier existe déjà", "Select template" : "Sélectionnez un modèle", diff --git a/l10n/lt_LT.js b/l10n/lt_LT.js index 5fd316781d..823dc5ddca 100644 --- a/l10n/lt_LT.js +++ b/l10n/lt_LT.js @@ -83,7 +83,7 @@ OC.L10N.register( "Empty" : "Tuščias", "Anonymous guest" : "Anoniminis svečias", "%s (Guest)" : "%s (Svečias)", - "Edit office documents directly in your browser." : "Redaguokite raštinės dokumentus tiesiogiai savo naršyklėje.", + "Edit office documents directly in your browser." : "Redaguokite biuro dokumentus tiesiogiai savo naršyklėje.", "This application can connect to a Collabora Online (or other) server (WOPI-like Client). Nextcloud is the WOPI Host. Please read the documentation to learn more about that.\n\nYou can also edit your documents off-line with the Collabora Office app from the **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** and **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** store." : "Ši programėlė gali prisijungti prie „Collabora Online“ (ar kito) serverio (WOPI tipo klientas). „Nextcloud“ yra WOPI mazgas. Daugiau informacijos apie tai rasite dokumentacijoje.\n\nDokumentus taip pat galite redaguoti neprisijungę prie interneto naudodami „Collabora Office“ programėlę, kurią galite atsisiųsti iš **[„Android“](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** ir **[„iOS“](https://apps.apple.com/us/app/collabora-office/id1440482071)** parduotuvių.", "Instance-wide templates that should be available to all users." : "Viso egzemplioriaus šablonai, kurie turėtų būti prieinami visiems vartotojams.", "Uploaded template \"{name}\"" : "Įkeltas šablonas „{name}“", @@ -104,33 +104,109 @@ OC.L10N.register( "Setting up a new server" : "Naujo serverio nustatymas", "Collabora Online should use the same protocol as the server installation." : "„Collabora Online“ turėtų naudoti tą patį protokolą kaip ir serverio diegimas.", "Your browser has been unable to connect to the Collabora server:" : "Jūsų naršyklė negalėjo prisijungti prie „Collabora“ serverio:", + "This URL is determined on the Collabora server either from the configured URL or the server_name parameter in coolwsd.xml." : "Šis URL adresas Collabora serveryje nustatomas pagal sukonfigūruotą URL adresą arba pagal parametrą „server_name“ failo „coolwsd.xml“.", "Collabora Online server is reachable." : "Collabora Online serveris yra pasiekiamas.", "URL used by the browser:" : "Naršyklės naudojamas URL adresas:", "Nextcloud URL used by Collabora:" : "Collabora naudojamas Nextcloud URL adresas:", + "Please configure a Collabora Online server to start editing documents" : "Prašome sukonfigūruoti „Collabora Online“ serverį, kad būtų galima pradėti redaguoti dokumentus", + "You have not configured the allow-list for WOPI requests. Without this setting users may download restricted files via WOPI requests to the Nextcloud server." : "Jūs nesukonfigūravote WOPI užklausų leidžiamų sąrašo. Be šio nustatymo vartotojai gali atsisiųsti ribojamus failus į „Nextcloud“ serverį naudodami WOPI užklausas.", + "Click here for more info" : "Spauskite čia, jei norite sužinoti daugiau", "Use your own server" : "Naudoti asmeninį serverį", - "Disable certificate verification (insecure)" : "Išjungti liudijimų tikrinimą (nesaugu)", + "Nextcloud Office requires a separate server running Collabora Online to provide editing capabilities." : "Kad „Nextcloud Office“ galėtų teikti redagavimo funkcijas, reikalingas atskiras serveris, kuriame veikia „Collabora Online“.", + "Collabora Online requires a separate server acting as a WOPI-like Client to provide editing capabilities." : "Kad būtų galima redaguoti dokumentus, „Collabora Online“ reikia atskiro serverio, veikiančio kaip WAPI tipo klientas.", + "URL (and Port) of Collabora Online-server" : "„Collabora Online“ serverio URL (ir prievadas)", + "Disable certificate verification (insecure)" : "Išjungti sertifikatų tikrinimą (nesaugu)", + "Enable if your Collabora Online server uses a self signed certificate" : "Įjunkite šią parinktį, jei jūsų „Collabora Online“ serveris naudoja savarankiškai pasirašytą sertifikatą", + "Use the built-in CODE - Collabora Online Development Edition" : "Naudokite integruotą CODE – „Collabora Online Development Edition“", + "Easy to install, for home use or small groups. A bit slower than a standalone server and without the advanced scalability features." : "Lengva įdiegti, skirta naudoti namuose ar mažose grupėse. Veikia šiek tiek lėčiau nei atskirasis serveris ir neturi pažangių plečiamumo funkcijų.", + "This installation does not have a built in server." : "Šioje įdiegtyje nėra integruoto serverio.", + "Install it from the App Store." : "Įdiekite ją iš „App Store“.", + "If the installation from the App Store fails, you can still do that manually using this command:" : "Jei įdiegti iš „App Store“ nepavyksta, vis tiek galite tai padaryti rankiniu būdu naudodami šią komandą:", "Use a demo server" : "Naudoti demonstracinį serverį", + "You can use a demo server provided by Collabora and other service providers for giving Collabora Online a try." : "Norėdami išbandyti „Collabora Online“, galite pasinaudoti „Collabora“ ar kitų paslaugų teikėjų siūlomu demonstraciniu serveriu.", "Your Nextcloud setup is not capable of connecting to the demo servers because:" : "Jūsų Nextcloud sąranka negali prisijungti prie demonstracinių serverių, nes:", "it is a local setup (localhost)" : "tai yra vietinė sąranka (localhost)", "it uses an insecure protocol (HTTP)" : "ji naudoja nesaugų protokolą (HTTP)", "it is unreachable from the internet (possibly because of a firewall, or lack of port forwarding)" : "ji yra nepasiekiama iš interneto (galimai, dėl užkardos ar neperadresuotų prievadų)", + "For use cases like this, we offer instructions for a" : "Tokiems atvejams siūlome instrukcijas, kaip naudoti", + "Quick tryout with Nextcloud docker." : "Greitas „Nextcloud“ „Docker“ išbandymas.", "Loading available demo servers …" : "Įkeliami prieinami demonstraciniai serveriai…", "No available demo servers found." : "Nerasta jokių prieinamų demonstracinių serverių.", + "Documents opened with the demo server configured will be sent to a 3rd party server. Only use this for evaluating Collabora Online." : "Dokumentai, atidaryti su konfigūruotu demonstraciniu serveriu, bus siunčiami į trečiosios šalies serverį. Naudokite jį tik „Collabora Online“ vertinimui.", + "Please make sure you understand that the following will happen if you set up the Collabora Online demo." : "Prašome įsitikinti, kad suprantate, jog įdiegus „Collabora Online“ demonstracinę versiją įvyks toliau sekantys dalykai.", + "The service will send users documents to Collabora and/or third party demo servers." : "Ši paslauga siųs vartotojų dokumentus į „Collabora“ ir (arba) trečiųjų šalių demonstracinius serverius.", + "This service is not intended for production use, hence the documents will show tile watermarks." : "Ši paslauga nėra skirta gamybiniam naudojimui, todėl dokumentuose bus matomi plytelių formos vandenženklai.", + "The demo service may be under heavy load, and its performance is not representative in any way of the performance of an on-premise installation." : "Demo paslauga gali būti labai apkrauta, todėl jos veikimas jokiu būdu neatspindi vietinės įrangos veikimo.", + "These servers are used for testing and development, and may run test versions of the software. As such they may crash, burn, and re-start without warning." : "Šie serveriai skirti bandymams ir programinės įrangos kūrimui, todėl juose gali būti įdiegtos programinės įrangos bandomosios versijos. Dėl to jie gali be įspėjimo užstrigti, išsijungti ir vėl paleisti.", + "The users documents will not be retained by a third party after their session completes except in exceptional circumstances. By using the service, the user gives permission for Collabora engineers to exceptionally use such document data, solely for the purpose of providing, optimizing and improving Collabora Online. Such document data will remain confidential to Collabora and/or any third party providing a demo server." : "Vartotojų dokumentai nebus saugomi trečiųjų šalių po to, kai baigsis jų sesija, išskyrus išimtinius atvejus. Naudodamasis paslauga, vartotojas suteikia leidimą „Collabora“ inžinieriams išimtiniais atvejais naudoti tokius dokumentų duomenis, siekiant tik teikti, optimizuoti ir tobulinti „Collabora Online“. Tokie dokumentų duomenys liks konfidencialūs „Collabora“ ir (arba) bet kuriai trečiajai šaliai, teikiančiai demonstracinį serverį.", + "At the first use and after an update, each user will get the warning, explaining all the above." : "Pirmą kartą naudodamasis programa arba po jos atnaujinimo kiekvienas vartotojas gaus įspėjimą, kuriame bus paaiškinta visa tai, kas išdėstyta aukščiau.", + "I agree, and use the demo server" : "Sutinku, ir naudojuosi demonstraciniu serveriu", "I will setup my own server" : "Aš nusistatysiu asmeninį serverį", "Advanced settings" : "Išplėstiniai nustatymai", + "Use Office Open XML (OOXML) instead of OpenDocument Format (ODF) by default for new files" : "Naujiems failams pagal numatytuosius nustatymus naudoti „Office Open XML“ (OOXML) vietoj „OpenDocument Format“ (ODF)", + "Restrict usage to specific groups" : "Apriboti naudojimą tik tam tikroms grupėms", + "{productName} is enabled for all users by default. When this setting is active, only members of the specified groups can use it." : "{productName} pagal numatytuosius nustatymus įjungtas visiems vartotojams. Kai šis nustatymas aktyvus, jį gali naudoti tik nurodytų grupių nariai.", "Select groups" : "Pasirinkti grupes", + "Restrict edit to specific groups" : "Leisti redaguoti tik tam tikroms grupėms", + "All users can edit documents with {productName} by default. When this setting is active, only the members of the specified groups can edit, whereas the others can only view documents." : "Pagal numatytuosius nustatymus visi vartotojai gali redaguoti dokumentus naudodami {productName}. Kai šis nustatymas aktyvus, redaguoti gali tik nurodytų grupių nariai, o kiti – tik peržiūrėti dokumentus.", + "Use Canonical webroot" : "Naudoti kanoninį žiniatinklio šakninį katalogą", + "Canonical webroot, in case there are multiple, for Collabora to use. Provide the one with least restrictions. Eg: Use non-shibbolized webroot if this instance is accessed by both shibbolized and non-shibbolized webroots. You can ignore this setting if only one webroot is used to access this instance." : "Kanoninis žiniatinklio šakninis katalogas (jei jų yra keli), kurį naudos „Collabora“. Nurodykite tą, kuriam taikoma mažiausiai apribojimų. Pavyzdžiui: naudokite ne „shibboleth“ tipo katalogą, jei šis „Nextcloud“ elementas pasiekiamas tiek per „shibboleth“, tiek per paprastus šakninius katalogus. Galite nepaisyti šio nustatymo, jei elementui pasiekti naudojamas tik vienas katalogas.", + "Enable access for external apps" : "Įgalinti prieigą išorinėms programėlėms", + "List of IPV4 and IPV6 IP-addresses and subnets that are allowed to perform requests of the WOPI endpoints. If no allow list is specified all hosts will be allowed. E.g. 10.0.0.20,10.0.4.0/24" : "IPv4 ir IPv6 adresų bei potinklių, kuriems leidžiama teikti užklausas WOPI galiniams taškams, sąrašas. Jei leidžiamų adresų sąrašas nenurodytas, prieiga bus leidžiama visiems įrenginiams (arba mazgams). Pvz., 10.0.0.20,10.0.4.0/24", "Custom Fonts" : "Tinkinti šriftai", + "Upload font file" : "Įkelti šrifto failą", + "Upload a font file" : "Įkelti šrifto failą", "Available fonts" : "Prieinami šriftai", + "For ideal document compatibility we recommend you to install commonly used fonts. If your users are working with Microsoft Office, installing their proprietary fonts can be done following the documentation." : "Siekiant užtikrinti optimalų dokumentų suderinamumą, rekomenduojame įdiegti dažniausiai naudojamus šriftus. Jei jūsų vartotojai dirba su „Microsoft Office“, jų nuosavus šriftus galima įdiegti vadovaujantis instrukcijomis.", "Custom fonts documentation" : "Tinkintų šriftų dokumentacija", + "Secure View" : "Saugus peržiūros režimas", + "Secure view enables you to secure office documents by blocking downloads, previews and showing a watermark" : "Saugus peržiūros režimas leidžia apsaugoti biuro dokumentus, užblokuojant jų atsisiuntimą, peržiūrą ir rodant vandenženklį", + "The settings only apply to compatible office files that are opened in Nextcloud Office" : "Šie nustatymai taikomi tik suderinamiems „Office“ failams, atidarytiems „Nextcloud Office“", + "Downloading the file through WebDAV will be blocked" : "Failo atsisiuntimas per WebDAV bus užblokuotas", + "The following options within Nextcloud Office will be disabled: Copy, Download, Export, Print" : "„Nextcloud Office“ bus išjungtos šios funkcijos: kopijuoti, atsisiųsti, eksportuoti, spausdinti", + "Files may still be downloadable via WOPI requests if WOPI settings are not correctly configured" : "Jei WOPI nustatymai nėra tinkamai sukonfigūruoti, failus vis tiek galima atsisiųsti naudojant WOPI užklausas", + "Previews will be blocked" : "Peržiūros bus blokuojamos", + "Enable secure view" : "Įjungti saugų peržiūros režimą", + "Supported placeholders: {userId}, {userDisplayName}, {email}, {date}, {themingName}" : "Palaikomi vietos žymekliai: {userId}, {userDisplayName}, {email}, {date}, {themingName}", + "Enforce secure view on tagged files" : "Įjungti saugų rodinį pažymėtiems failams", + "Select tags to enforce watermarking" : "Pasirinkite žymes, kurioms taikyti vandenženklį", + "Enforce secure view for users of groups" : "Įjungti saugų rodinį režimą grupių nariams", + "Enforce secure view for all shares" : "Įjungti saugų rodinį visoms bendrinamoms nuorodoms", + "Enforce secure view for read only shares" : "Įjungti saugų rodinį tik skaitymo bendrinimams", + "Enforce secure view for all public Talk shares" : "Įjungti saugų rodinį visiems viešiems „Talk“ bendrinimams", + "Enforce secure view for shares without download permission" : "Įjungti saugų rodinį bendrinamiems asmenims be atsisiuntimo leidimo", + "Enforce secure view for all link shares" : "Įjungti saugų rodinį visoms bendrinamoms nuorodoms", + "Enforce secure view for download hidden shares" : "Įjungti saugų rodinį atsisiunčiant paslėptus bendrinimus", + "Enforce secure view for read only link shares" : "Įjungti saugų rodinį tik skaitymo nuorodų bendrinimams", + "Enforce secure view on link shares with specific system tags" : "Įgalinti saugų rodinį bendrinant nuorodas su konkrečiomis sistemos žymėmis", + "Select tags to enforce secure view" : "Pasirinkite žymas, kad būtų užtikrintas saugus rodinys", + "Electronic Signature" : "Elektroninis parašas", + "Client ID for the electronic signature API" : "Elektroninio parašo API kliento ID", + "Fill in the registration form at https://eideasy.com/signup to obtain a client ID and secret." : "Užpildykite registracijos formą adresu https://eideasy.com/signup, kad gautumėte kliento ID ir slaptažodį.", + "Secret for the electronic signature API" : "Elektroninio parašo API raktas", + "The secret may be downloadable via WOPI requests if WOPI allow list is not correctly configured." : "Jei WOPI leidžiamųjų sąrašas neteisingai sukonfigūruotas, slaptą kodą galima atsisiųsti per WOPI užklausas.", "Save" : "Įrašyti", "Remove" : "Šalinti", + "Please enter the guest name you wish to use before proceeding to the document. If you don't provide one, the default will be used." : "Prieš pereidami prie dokumento, įveskite norimą svečio vardą. Jei jo nenurodysite, bus naudojamas numatytasis vardas.", + "Guest name" : "Svečio vardas", + "Submit name" : "Įveskite vardą", "Confirm" : "Patvirtinti", "Cancel" : "Atsisakyti", "Save As" : "Įrašyti kaip", + "A file with that name already exists." : "Failas su tokiu pavadinimu jau egzistuoja.", + "Error checking if file exists." : "Klaida tikrinant, ar failas egzistuoja.", "Save as" : "Įrašyti kaip", + "Path to save" : "Kelią į išsaugojimo vietą", + "Checking…" : "Tikrinama...", + "Invalid file name" : "Neteisingas failo pavadinimas", + "File name already exists" : "Failo pavadinimas jau yra", "Select template" : "Pasirinkite šabloną", "File name" : "Failo pavadinimas", "Create" : "Sukurti", + "Failed to set Zotero API key" : "Nepavyko nustatyti „Zotero“ API rakto", + "Link to your Zotero library" : "Nuoroda į jūsų „Zotero“ biblioteką", + "Connect your Zotero account to make use of references within Office." : "Prijunkite savo „Zotero“ paskyrą, kad galėtumėte naudoti nuorodas „Office“ programoje.", + "You can generate an account key here:" : "Paskyros raktą galite sugeneruoti čia:", "Zotero account settings" : "„Zotero“ paskyros nustatymai", "Zotero API key" : "„Zotero“ API raktas", "Submit" : "Pateikti", @@ -138,26 +214,59 @@ OC.L10N.register( "Settings saved successfully." : "Nustatymai sėkmingai įrašyti.", "Failed to save settings." : "Nepavyko įrašyti nustatymų.", "Unexpected error occurred." : "Įvyko netikėta klaida.", + "Personal Settings for Nextcloud Office" : "Asmeniniai „Nextcloud Office“ nustatymai", "Select a template directory" : "Pasirinkite šablonų katalogą", + "Remove personal template folder" : "Pašalinkite asmeninio šablono aplanką", + "Templates inside of this directory will be added to the template selector of Nextcloud Office." : "Šiame kataloge esantys šablonai bus įtraukti į „Nextcloud Office“ šablonų pasirinkimo meniu.", + "Document signing" : "Dokumento pasirašymas", + "Enter document signing cert (in PEM format)" : "Įveskite dokumento pasirašymo sertifikatą (PEM formatu)", + "Enter document signing key" : "Įveskite dokumento pasirašymo raktą", + "Enter document signing CA chain" : "Įveskite dokumentų pasirašymo CA grandinę", + "To use document signing, specify your signing certificate, key and CA chain here." : "Norėdami naudoti dokumentų pasirašymą, čia nurodykite savo pasirašymo sertifikatą, raktą ir CA grandinę.", + "This instance does not support document signing, because the feature is missing or disabled. Please contact the administrator." : "Šis egzempliorius nepalaiko dokumentų pasirašymo, nes funkcijos nėra arba ji išjungta. Susisiekite su administratoriumi.", "Description" : "Aprašas", - "Add new token" : "Pridėti naują prieigos raktą", + "Add new token" : "Pridėti naują žymą", + "No font overview" : "Nėra šriftų apžvalgos", "Delete this font" : "Ištrinti šį šriftą", "No results" : "Rezultatų nėra", "Select file" : "Pasirinkti failą", "Select file or folder to link to" : "Pasirinkite failą arba aplanką, į kurį norite susieti", + "Could not find any section in the document" : "Dokumente nerasta jokio skyriaus", "{productName} is not configured" : "{productName} nesukonfigūruota", + "Starting the built-in CODE server failed" : "Nepavyko paleisti integruoto CODE serverio", "Loading {filename} …" : "Įkeliamas {filename}…", "Preview" : "Peržiūra", "Edit" : "Taisyti", "Failed to load {productName} - please try again later" : "Nepavyko įkelti {productName} – vėliau bandykite dar kartą", "Open in local editor" : "Atverti vietiniame redaktoriuje", + "Cluster is scaling …" : "Klasteris plečiasi…", + "The collaborative editing was terminated by another user" : "Bendradarbiavimo redagavimą nutraukė kitas vartotojas", "Document loading failed" : "Nepavyko įkelti dokumento", + "Please check the Collabora Online server log for more details and make sure that Nextcloud can be reached from there." : "Daugiau informacijos rasite „Collabora Online“ serverio žurnale ir įsitikinkite, kad iš ten galima pasiekti „Nextcloud“.", + "Socket connection closed unexpectedly. The reverse proxy might be misconfigured, please contact the administrator." : "Sąsaja su lizdu netikėtai uždaryta. Galbūt atvirkštinis tarpinis serveris yra netinkamai sukonfigūruotas, kreipkitės į administratorių.", + "More information can be found in the reverse proxy documentation" : "Daugiau informacijos galite rasti atvirkštinio tarpinio serverio dokumentacijoje.", "Close" : "Užverti", + "Built-in CODE Server is starting up shortly, please wait." : "Integruotas CODE serveris netrukus bus paleistas, palaukite.", + "Built-in CODE Server is restarting, please wait." : "Integruotas CODE serveris paleidžiamas iš naujo, palaukite.", + "Error: Cannot find the AppImage, please reinstall the Collabora Online Built-in server." : "Klaida: Negaliu rasti „AppImage“, iš naujo įdiekite integruotą „Collabora Online“ serverį.", + "Error: Unable to make the AppImage executable, please setup a standalone server." : "Klaida: Nepavyko paleisti „AppImage“, nustatykite atskirą serverį.", + "Error: Exec disabled in PHP, please enable it, or setup a standalone server." : "Klaida: PHP funkcija „exec“ išjungta. Įjunkite ją arba sukonfigūruokite atskirą serverį.", + "Error: Not running on x86-64 or ARM64 (aarch64) Linux, please setup a standalone server." : "Klaida: Sistema neveikia „Linux“ aplinkoje su „x86-64“ arba „ARM64“ (aarch64) architektūra. Prašome įdiegti atskirą serverį.", + "Error: The fontconfig library is not installed on your server, please install it or setup a standalone server." : "Klaida: jūsų serveryje neįdiegta „fontconfig“ biblioteka. Įdiekite ją arba sukonfigūruokite atskirą serverį.", + "Error: Not running on glibc-based Linux, please setup a standalone server." : "Klaida: neveikia „Linux“ sistemoje, pagrįstoje „glibc“ biblioteka. Prašome įdiegti atskirą serverį.", + "Error: Cannot start the Collabora Online Built-in server, please setup a standalone one." : "Klaida: Nepavyksta paleisti „Collabora Online“ integruoto serverio. Įdiekite atskirą serverį.", "Close version preview" : "Užverti versijos peržiūrą", "Edit with {productName}" : "Taisyti naudojant {productName}", + "Insert into document" : "Įterpti į dokumentą", "Open file locally" : "Atidaryti failą vietoje", + "When opening a file locally, the document will close for all users currently viewing the document." : "Atidarant failą lokaliai, dokumentas bus uždarytas visiems vartotojams, šiuo metu jį peržiūrintiems.", "Open locally" : "Atidaryti vietoje", + "Continue editing online" : "Tęsti redagavimą internete", + "The file should now open locally. If you don't see this happening, make sure that the desktop client is installed on your system." : "Failas dabar turėtų atsidaryti lokaliai. Jei nematote, kad tai įvyktų, įsitikinkite, kad jūsų sistemoje įdiegta darbalaukio programa.", + "Retry to open locally" : "Pabandykite atidaryti lokaliai", + "Save a copy of the file under a new name and continue editing the new file" : "Išsaugoti failo kopiją nauju pavadinimu ir tęsti naujo failo redagavimą", "Failed to revert the document to older version" : "Nepavyko sugrąžinti dokumentą į senesnę versiją", + "Built-in CODE server failed to start" : "Nepavyko paleisti integruoto CODE serverio", "Insert file from {name}" : "Įterpti failą iš {name}", "Insert file" : "Įterpti failą", "Remove from favorites" : "Pašalinti iš mėgstamų", @@ -167,19 +276,34 @@ OC.L10N.register( "(read only)" : "(tik skaitymui)", "Remove user" : "Šalinti naudotoją", "Guest" : "Svečias", + "Follow current editor" : "Sekite dabartinį redaktorių", "New file" : "Naujas failas", + "Please enter the filename for the new file" : "Įveskite naujo failo pavadinimą", "Saved with error: Collabora Online should use the same protocol as the server installation." : "Įrašyta su klaida: Collabora Online turėtų naudoti tokį patį protokolą kaip ir serverio diegimas.", + "Could not establish connection to the Collabora Online server. This might be due to a missing configuration of your web server. For more information, please visit: " : "Nepavyko užmegzti ryšio su „Collabora Online“ serveriu. Tai gali būti susiję su netinkamai sukonfigūruotu jūsų žiniatinklio serveriu. Daugiau informacijos rasite: ", + "Nextcloud Office requires a seperate server running Collabora Online to provide editing capabilities." : "„Nextcloud Office“ redagavimo galimybėms užtikrinti reikalingas atskiras serveris, kuriame veikia „Collabora Online“.", + "Collabora Online requires a seperate server acting as a WOPI-like Client to provide editing capabilities." : "„Collabora Online“ redagavimo galimybėms užtikrinti reikalingas atskiras serveris, veikiantis kaip WOPI tipo klientas.", + "All users can edit documents with {productName} by default. When this setting is active, only the members of the specified groups can edit and the others can only view documents." : "Pagal numatytuosius nustatymus visi vartotojai gali redaguoti dokumentus su {productName}. Kai šis nustatymas aktyvus, dokumentus gali redaguoti tik nurodytų grupių nariai, o kiti – tik peržiūrėti.", "Secure view settings" : "Saugaus rodinio nustatymai", "Secure view enables you to secure documents by embedding a watermark" : "Saugusis rodinys leidžia jums apsaugoti dokumentus įterpiant vandenženklį", "Enable watermarking" : "Įjungti vandenženklių darymą", "Show watermark on tagged files" : "Rodyti vandenženklį ant failų, turinčių žymas", + "Show watermark for users of groups" : "Rodyti vandenženklį grupių naudotojams", + "Show watermark for all shares" : "Rodyti vandenženklį visose dalinimosi nuorodose", + "Show watermark for read only shares" : "Rodyti vandenženklį bendrinimams, skirtiems tik skaitymui", + "Show watermark for all link shares" : "Rodyti vandens ženklą visiems nuorodų bendrinimams", + "Show watermark for download hidden shares" : "Rodyti vandenženklį bendrinimams su paslėptu atsisiuntimu", + "Show watermark for read only link shares" : "Rodyti vandenženklį tik skaitymo nuorodų bendrinimams", + "Show watermark on link shares with specific system tags" : "Rodyti vandenženklį bendrinamose nuorodose su konkrečiomis sistemos žymėmis", "Error" : "Klaida", "An error occurred" : "Įvyko klaida", "Please choose your nickname to continue as guest user." : "Norėdami tęsti kaip svečias, pasirinkite savo slapyvardį.", "Nickname" : "Slapyvardis", "Set" : "Nustatyti", - "Please enter the filename to store the document as." : "Įveskite naują pavadinimą, kuriuo bus saugomas dokumentas.", + "Please enter the filename to store the document as." : "Įveskite failo pavadinimą, kuriuo bus saugomas dokumentas.", "New filename" : "Naujas failo pavadinimas", + "Collabora Online is not setup yet. Please contact your administrator." : "„Collabora Online“ dar nėra sukonfigūruota. Kreipkitės į savo administratorių.", + "Opening the file is not supported, since the credentials for the external storage are not available without a session" : "Failo atidarymas nepalaikomas, nes be sesijos nėra prieigos duomenų prie išorinės saugyklos", "Failed to connect to {productName}. Please try again later or contact your server administrator." : "Nepavyko prisijungti prie {productName}. Vėliau bandykite dar kartą arba susisiekite su savo serverio administratoriumi.", "Saving…" : "Įrašoma…", "Insert from {name}" : "Įterpti iš {name}", @@ -194,7 +318,13 @@ OC.L10N.register( "No templates defined." : "Neapibrėžtas joks šablonas.", "Add a new one?" : "Pridėti naują?", "template preview" : "šablono peržiūra", + "Files may still be downloadable through Nextcloud unless restricted otherwise through sharing or access control settings" : "Failus vis dar galima atsisiųsti per „Nextcloud“, jei tai nėra apribota bendrinimo ar prieigos kontrolės nustatymuose", + "Previews will be blocked for watermarked files to not leak the first page of documents" : "Failų su vandenženkliu peržiūra bus užblokuota, kad nebūtų atskleista dokumentų pirmoji puslapis", + "Show watermark for shares without download permission" : "Rodyti vandenženklį dalinamiesiems failams, kurių negalima atsisiųsti", + "New drawing" : "Naujas piešinys", "Collabora Online" : "Collabora Online", - "Document already exists" : "Dokumentas jau yra" + "Document already exists" : "Dokumentas jau yra", + "Collabora Online is enabled for all users by default. When this setting is active, only members of the specified groups can use it." : "„Collabora Online“ funkcija visiems vartotojams įjungta pagal numatytuosius nustatymus. Kai šis nustatymas aktyvus, ja gali naudotis tik nurodytų grupių nariai.", + "Templates inside of this directory will be added to the template selector of Collabora Online." : "Šiame kataloge esantys šablonai bus įtraukti į „Collabora Online“ šablonų pasirinkimo sąrašą." }, "nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);"); diff --git a/l10n/lt_LT.json b/l10n/lt_LT.json index c6f04357e1..58fe1dbcce 100644 --- a/l10n/lt_LT.json +++ b/l10n/lt_LT.json @@ -81,7 +81,7 @@ "Empty" : "Tuščias", "Anonymous guest" : "Anoniminis svečias", "%s (Guest)" : "%s (Svečias)", - "Edit office documents directly in your browser." : "Redaguokite raštinės dokumentus tiesiogiai savo naršyklėje.", + "Edit office documents directly in your browser." : "Redaguokite biuro dokumentus tiesiogiai savo naršyklėje.", "This application can connect to a Collabora Online (or other) server (WOPI-like Client). Nextcloud is the WOPI Host. Please read the documentation to learn more about that.\n\nYou can also edit your documents off-line with the Collabora Office app from the **[Android](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** and **[iOS](https://apps.apple.com/us/app/collabora-office/id1440482071)** store." : "Ši programėlė gali prisijungti prie „Collabora Online“ (ar kito) serverio (WOPI tipo klientas). „Nextcloud“ yra WOPI mazgas. Daugiau informacijos apie tai rasite dokumentacijoje.\n\nDokumentus taip pat galite redaguoti neprisijungę prie interneto naudodami „Collabora Office“ programėlę, kurią galite atsisiųsti iš **[„Android“](https://play.google.com/store/apps/details?id=com.collabora.libreoffice)** ir **[„iOS“](https://apps.apple.com/us/app/collabora-office/id1440482071)** parduotuvių.", "Instance-wide templates that should be available to all users." : "Viso egzemplioriaus šablonai, kurie turėtų būti prieinami visiems vartotojams.", "Uploaded template \"{name}\"" : "Įkeltas šablonas „{name}“", @@ -102,33 +102,109 @@ "Setting up a new server" : "Naujo serverio nustatymas", "Collabora Online should use the same protocol as the server installation." : "„Collabora Online“ turėtų naudoti tą patį protokolą kaip ir serverio diegimas.", "Your browser has been unable to connect to the Collabora server:" : "Jūsų naršyklė negalėjo prisijungti prie „Collabora“ serverio:", + "This URL is determined on the Collabora server either from the configured URL or the server_name parameter in coolwsd.xml." : "Šis URL adresas Collabora serveryje nustatomas pagal sukonfigūruotą URL adresą arba pagal parametrą „server_name“ failo „coolwsd.xml“.", "Collabora Online server is reachable." : "Collabora Online serveris yra pasiekiamas.", "URL used by the browser:" : "Naršyklės naudojamas URL adresas:", "Nextcloud URL used by Collabora:" : "Collabora naudojamas Nextcloud URL adresas:", + "Please configure a Collabora Online server to start editing documents" : "Prašome sukonfigūruoti „Collabora Online“ serverį, kad būtų galima pradėti redaguoti dokumentus", + "You have not configured the allow-list for WOPI requests. Without this setting users may download restricted files via WOPI requests to the Nextcloud server." : "Jūs nesukonfigūravote WOPI užklausų leidžiamų sąrašo. Be šio nustatymo vartotojai gali atsisiųsti ribojamus failus į „Nextcloud“ serverį naudodami WOPI užklausas.", + "Click here for more info" : "Spauskite čia, jei norite sužinoti daugiau", "Use your own server" : "Naudoti asmeninį serverį", - "Disable certificate verification (insecure)" : "Išjungti liudijimų tikrinimą (nesaugu)", + "Nextcloud Office requires a separate server running Collabora Online to provide editing capabilities." : "Kad „Nextcloud Office“ galėtų teikti redagavimo funkcijas, reikalingas atskiras serveris, kuriame veikia „Collabora Online“.", + "Collabora Online requires a separate server acting as a WOPI-like Client to provide editing capabilities." : "Kad būtų galima redaguoti dokumentus, „Collabora Online“ reikia atskiro serverio, veikiančio kaip WAPI tipo klientas.", + "URL (and Port) of Collabora Online-server" : "„Collabora Online“ serverio URL (ir prievadas)", + "Disable certificate verification (insecure)" : "Išjungti sertifikatų tikrinimą (nesaugu)", + "Enable if your Collabora Online server uses a self signed certificate" : "Įjunkite šią parinktį, jei jūsų „Collabora Online“ serveris naudoja savarankiškai pasirašytą sertifikatą", + "Use the built-in CODE - Collabora Online Development Edition" : "Naudokite integruotą CODE – „Collabora Online Development Edition“", + "Easy to install, for home use or small groups. A bit slower than a standalone server and without the advanced scalability features." : "Lengva įdiegti, skirta naudoti namuose ar mažose grupėse. Veikia šiek tiek lėčiau nei atskirasis serveris ir neturi pažangių plečiamumo funkcijų.", + "This installation does not have a built in server." : "Šioje įdiegtyje nėra integruoto serverio.", + "Install it from the App Store." : "Įdiekite ją iš „App Store“.", + "If the installation from the App Store fails, you can still do that manually using this command:" : "Jei įdiegti iš „App Store“ nepavyksta, vis tiek galite tai padaryti rankiniu būdu naudodami šią komandą:", "Use a demo server" : "Naudoti demonstracinį serverį", + "You can use a demo server provided by Collabora and other service providers for giving Collabora Online a try." : "Norėdami išbandyti „Collabora Online“, galite pasinaudoti „Collabora“ ar kitų paslaugų teikėjų siūlomu demonstraciniu serveriu.", "Your Nextcloud setup is not capable of connecting to the demo servers because:" : "Jūsų Nextcloud sąranka negali prisijungti prie demonstracinių serverių, nes:", "it is a local setup (localhost)" : "tai yra vietinė sąranka (localhost)", "it uses an insecure protocol (HTTP)" : "ji naudoja nesaugų protokolą (HTTP)", "it is unreachable from the internet (possibly because of a firewall, or lack of port forwarding)" : "ji yra nepasiekiama iš interneto (galimai, dėl užkardos ar neperadresuotų prievadų)", + "For use cases like this, we offer instructions for a" : "Tokiems atvejams siūlome instrukcijas, kaip naudoti", + "Quick tryout with Nextcloud docker." : "Greitas „Nextcloud“ „Docker“ išbandymas.", "Loading available demo servers …" : "Įkeliami prieinami demonstraciniai serveriai…", "No available demo servers found." : "Nerasta jokių prieinamų demonstracinių serverių.", + "Documents opened with the demo server configured will be sent to a 3rd party server. Only use this for evaluating Collabora Online." : "Dokumentai, atidaryti su konfigūruotu demonstraciniu serveriu, bus siunčiami į trečiosios šalies serverį. Naudokite jį tik „Collabora Online“ vertinimui.", + "Please make sure you understand that the following will happen if you set up the Collabora Online demo." : "Prašome įsitikinti, kad suprantate, jog įdiegus „Collabora Online“ demonstracinę versiją įvyks toliau sekantys dalykai.", + "The service will send users documents to Collabora and/or third party demo servers." : "Ši paslauga siųs vartotojų dokumentus į „Collabora“ ir (arba) trečiųjų šalių demonstracinius serverius.", + "This service is not intended for production use, hence the documents will show tile watermarks." : "Ši paslauga nėra skirta gamybiniam naudojimui, todėl dokumentuose bus matomi plytelių formos vandenženklai.", + "The demo service may be under heavy load, and its performance is not representative in any way of the performance of an on-premise installation." : "Demo paslauga gali būti labai apkrauta, todėl jos veikimas jokiu būdu neatspindi vietinės įrangos veikimo.", + "These servers are used for testing and development, and may run test versions of the software. As such they may crash, burn, and re-start without warning." : "Šie serveriai skirti bandymams ir programinės įrangos kūrimui, todėl juose gali būti įdiegtos programinės įrangos bandomosios versijos. Dėl to jie gali be įspėjimo užstrigti, išsijungti ir vėl paleisti.", + "The users documents will not be retained by a third party after their session completes except in exceptional circumstances. By using the service, the user gives permission for Collabora engineers to exceptionally use such document data, solely for the purpose of providing, optimizing and improving Collabora Online. Such document data will remain confidential to Collabora and/or any third party providing a demo server." : "Vartotojų dokumentai nebus saugomi trečiųjų šalių po to, kai baigsis jų sesija, išskyrus išimtinius atvejus. Naudodamasis paslauga, vartotojas suteikia leidimą „Collabora“ inžinieriams išimtiniais atvejais naudoti tokius dokumentų duomenis, siekiant tik teikti, optimizuoti ir tobulinti „Collabora Online“. Tokie dokumentų duomenys liks konfidencialūs „Collabora“ ir (arba) bet kuriai trečiajai šaliai, teikiančiai demonstracinį serverį.", + "At the first use and after an update, each user will get the warning, explaining all the above." : "Pirmą kartą naudodamasis programa arba po jos atnaujinimo kiekvienas vartotojas gaus įspėjimą, kuriame bus paaiškinta visa tai, kas išdėstyta aukščiau.", + "I agree, and use the demo server" : "Sutinku, ir naudojuosi demonstraciniu serveriu", "I will setup my own server" : "Aš nusistatysiu asmeninį serverį", "Advanced settings" : "Išplėstiniai nustatymai", + "Use Office Open XML (OOXML) instead of OpenDocument Format (ODF) by default for new files" : "Naujiems failams pagal numatytuosius nustatymus naudoti „Office Open XML“ (OOXML) vietoj „OpenDocument Format“ (ODF)", + "Restrict usage to specific groups" : "Apriboti naudojimą tik tam tikroms grupėms", + "{productName} is enabled for all users by default. When this setting is active, only members of the specified groups can use it." : "{productName} pagal numatytuosius nustatymus įjungtas visiems vartotojams. Kai šis nustatymas aktyvus, jį gali naudoti tik nurodytų grupių nariai.", "Select groups" : "Pasirinkti grupes", + "Restrict edit to specific groups" : "Leisti redaguoti tik tam tikroms grupėms", + "All users can edit documents with {productName} by default. When this setting is active, only the members of the specified groups can edit, whereas the others can only view documents." : "Pagal numatytuosius nustatymus visi vartotojai gali redaguoti dokumentus naudodami {productName}. Kai šis nustatymas aktyvus, redaguoti gali tik nurodytų grupių nariai, o kiti – tik peržiūrėti dokumentus.", + "Use Canonical webroot" : "Naudoti kanoninį žiniatinklio šakninį katalogą", + "Canonical webroot, in case there are multiple, for Collabora to use. Provide the one with least restrictions. Eg: Use non-shibbolized webroot if this instance is accessed by both shibbolized and non-shibbolized webroots. You can ignore this setting if only one webroot is used to access this instance." : "Kanoninis žiniatinklio šakninis katalogas (jei jų yra keli), kurį naudos „Collabora“. Nurodykite tą, kuriam taikoma mažiausiai apribojimų. Pavyzdžiui: naudokite ne „shibboleth“ tipo katalogą, jei šis „Nextcloud“ elementas pasiekiamas tiek per „shibboleth“, tiek per paprastus šakninius katalogus. Galite nepaisyti šio nustatymo, jei elementui pasiekti naudojamas tik vienas katalogas.", + "Enable access for external apps" : "Įgalinti prieigą išorinėms programėlėms", + "List of IPV4 and IPV6 IP-addresses and subnets that are allowed to perform requests of the WOPI endpoints. If no allow list is specified all hosts will be allowed. E.g. 10.0.0.20,10.0.4.0/24" : "IPv4 ir IPv6 adresų bei potinklių, kuriems leidžiama teikti užklausas WOPI galiniams taškams, sąrašas. Jei leidžiamų adresų sąrašas nenurodytas, prieiga bus leidžiama visiems įrenginiams (arba mazgams). Pvz., 10.0.0.20,10.0.4.0/24", "Custom Fonts" : "Tinkinti šriftai", + "Upload font file" : "Įkelti šrifto failą", + "Upload a font file" : "Įkelti šrifto failą", "Available fonts" : "Prieinami šriftai", + "For ideal document compatibility we recommend you to install commonly used fonts. If your users are working with Microsoft Office, installing their proprietary fonts can be done following the documentation." : "Siekiant užtikrinti optimalų dokumentų suderinamumą, rekomenduojame įdiegti dažniausiai naudojamus šriftus. Jei jūsų vartotojai dirba su „Microsoft Office“, jų nuosavus šriftus galima įdiegti vadovaujantis instrukcijomis.", "Custom fonts documentation" : "Tinkintų šriftų dokumentacija", + "Secure View" : "Saugus peržiūros režimas", + "Secure view enables you to secure office documents by blocking downloads, previews and showing a watermark" : "Saugus peržiūros režimas leidžia apsaugoti biuro dokumentus, užblokuojant jų atsisiuntimą, peržiūrą ir rodant vandenženklį", + "The settings only apply to compatible office files that are opened in Nextcloud Office" : "Šie nustatymai taikomi tik suderinamiems „Office“ failams, atidarytiems „Nextcloud Office“", + "Downloading the file through WebDAV will be blocked" : "Failo atsisiuntimas per WebDAV bus užblokuotas", + "The following options within Nextcloud Office will be disabled: Copy, Download, Export, Print" : "„Nextcloud Office“ bus išjungtos šios funkcijos: kopijuoti, atsisiųsti, eksportuoti, spausdinti", + "Files may still be downloadable via WOPI requests if WOPI settings are not correctly configured" : "Jei WOPI nustatymai nėra tinkamai sukonfigūruoti, failus vis tiek galima atsisiųsti naudojant WOPI užklausas", + "Previews will be blocked" : "Peržiūros bus blokuojamos", + "Enable secure view" : "Įjungti saugų peržiūros režimą", + "Supported placeholders: {userId}, {userDisplayName}, {email}, {date}, {themingName}" : "Palaikomi vietos žymekliai: {userId}, {userDisplayName}, {email}, {date}, {themingName}", + "Enforce secure view on tagged files" : "Įjungti saugų rodinį pažymėtiems failams", + "Select tags to enforce watermarking" : "Pasirinkite žymes, kurioms taikyti vandenženklį", + "Enforce secure view for users of groups" : "Įjungti saugų rodinį režimą grupių nariams", + "Enforce secure view for all shares" : "Įjungti saugų rodinį visoms bendrinamoms nuorodoms", + "Enforce secure view for read only shares" : "Įjungti saugų rodinį tik skaitymo bendrinimams", + "Enforce secure view for all public Talk shares" : "Įjungti saugų rodinį visiems viešiems „Talk“ bendrinimams", + "Enforce secure view for shares without download permission" : "Įjungti saugų rodinį bendrinamiems asmenims be atsisiuntimo leidimo", + "Enforce secure view for all link shares" : "Įjungti saugų rodinį visoms bendrinamoms nuorodoms", + "Enforce secure view for download hidden shares" : "Įjungti saugų rodinį atsisiunčiant paslėptus bendrinimus", + "Enforce secure view for read only link shares" : "Įjungti saugų rodinį tik skaitymo nuorodų bendrinimams", + "Enforce secure view on link shares with specific system tags" : "Įgalinti saugų rodinį bendrinant nuorodas su konkrečiomis sistemos žymėmis", + "Select tags to enforce secure view" : "Pasirinkite žymas, kad būtų užtikrintas saugus rodinys", + "Electronic Signature" : "Elektroninis parašas", + "Client ID for the electronic signature API" : "Elektroninio parašo API kliento ID", + "Fill in the registration form at https://eideasy.com/signup to obtain a client ID and secret." : "Užpildykite registracijos formą adresu https://eideasy.com/signup, kad gautumėte kliento ID ir slaptažodį.", + "Secret for the electronic signature API" : "Elektroninio parašo API raktas", + "The secret may be downloadable via WOPI requests if WOPI allow list is not correctly configured." : "Jei WOPI leidžiamųjų sąrašas neteisingai sukonfigūruotas, slaptą kodą galima atsisiųsti per WOPI užklausas.", "Save" : "Įrašyti", "Remove" : "Šalinti", + "Please enter the guest name you wish to use before proceeding to the document. If you don't provide one, the default will be used." : "Prieš pereidami prie dokumento, įveskite norimą svečio vardą. Jei jo nenurodysite, bus naudojamas numatytasis vardas.", + "Guest name" : "Svečio vardas", + "Submit name" : "Įveskite vardą", "Confirm" : "Patvirtinti", "Cancel" : "Atsisakyti", "Save As" : "Įrašyti kaip", + "A file with that name already exists." : "Failas su tokiu pavadinimu jau egzistuoja.", + "Error checking if file exists." : "Klaida tikrinant, ar failas egzistuoja.", "Save as" : "Įrašyti kaip", + "Path to save" : "Kelią į išsaugojimo vietą", + "Checking…" : "Tikrinama...", + "Invalid file name" : "Neteisingas failo pavadinimas", + "File name already exists" : "Failo pavadinimas jau yra", "Select template" : "Pasirinkite šabloną", "File name" : "Failo pavadinimas", "Create" : "Sukurti", + "Failed to set Zotero API key" : "Nepavyko nustatyti „Zotero“ API rakto", + "Link to your Zotero library" : "Nuoroda į jūsų „Zotero“ biblioteką", + "Connect your Zotero account to make use of references within Office." : "Prijunkite savo „Zotero“ paskyrą, kad galėtumėte naudoti nuorodas „Office“ programoje.", + "You can generate an account key here:" : "Paskyros raktą galite sugeneruoti čia:", "Zotero account settings" : "„Zotero“ paskyros nustatymai", "Zotero API key" : "„Zotero“ API raktas", "Submit" : "Pateikti", @@ -136,26 +212,59 @@ "Settings saved successfully." : "Nustatymai sėkmingai įrašyti.", "Failed to save settings." : "Nepavyko įrašyti nustatymų.", "Unexpected error occurred." : "Įvyko netikėta klaida.", + "Personal Settings for Nextcloud Office" : "Asmeniniai „Nextcloud Office“ nustatymai", "Select a template directory" : "Pasirinkite šablonų katalogą", + "Remove personal template folder" : "Pašalinkite asmeninio šablono aplanką", + "Templates inside of this directory will be added to the template selector of Nextcloud Office." : "Šiame kataloge esantys šablonai bus įtraukti į „Nextcloud Office“ šablonų pasirinkimo meniu.", + "Document signing" : "Dokumento pasirašymas", + "Enter document signing cert (in PEM format)" : "Įveskite dokumento pasirašymo sertifikatą (PEM formatu)", + "Enter document signing key" : "Įveskite dokumento pasirašymo raktą", + "Enter document signing CA chain" : "Įveskite dokumentų pasirašymo CA grandinę", + "To use document signing, specify your signing certificate, key and CA chain here." : "Norėdami naudoti dokumentų pasirašymą, čia nurodykite savo pasirašymo sertifikatą, raktą ir CA grandinę.", + "This instance does not support document signing, because the feature is missing or disabled. Please contact the administrator." : "Šis egzempliorius nepalaiko dokumentų pasirašymo, nes funkcijos nėra arba ji išjungta. Susisiekite su administratoriumi.", "Description" : "Aprašas", - "Add new token" : "Pridėti naują prieigos raktą", + "Add new token" : "Pridėti naują žymą", + "No font overview" : "Nėra šriftų apžvalgos", "Delete this font" : "Ištrinti šį šriftą", "No results" : "Rezultatų nėra", "Select file" : "Pasirinkti failą", "Select file or folder to link to" : "Pasirinkite failą arba aplanką, į kurį norite susieti", + "Could not find any section in the document" : "Dokumente nerasta jokio skyriaus", "{productName} is not configured" : "{productName} nesukonfigūruota", + "Starting the built-in CODE server failed" : "Nepavyko paleisti integruoto CODE serverio", "Loading {filename} …" : "Įkeliamas {filename}…", "Preview" : "Peržiūra", "Edit" : "Taisyti", "Failed to load {productName} - please try again later" : "Nepavyko įkelti {productName} – vėliau bandykite dar kartą", "Open in local editor" : "Atverti vietiniame redaktoriuje", + "Cluster is scaling …" : "Klasteris plečiasi…", + "The collaborative editing was terminated by another user" : "Bendradarbiavimo redagavimą nutraukė kitas vartotojas", "Document loading failed" : "Nepavyko įkelti dokumento", + "Please check the Collabora Online server log for more details and make sure that Nextcloud can be reached from there." : "Daugiau informacijos rasite „Collabora Online“ serverio žurnale ir įsitikinkite, kad iš ten galima pasiekti „Nextcloud“.", + "Socket connection closed unexpectedly. The reverse proxy might be misconfigured, please contact the administrator." : "Sąsaja su lizdu netikėtai uždaryta. Galbūt atvirkštinis tarpinis serveris yra netinkamai sukonfigūruotas, kreipkitės į administratorių.", + "More information can be found in the reverse proxy documentation" : "Daugiau informacijos galite rasti atvirkštinio tarpinio serverio dokumentacijoje.", "Close" : "Užverti", + "Built-in CODE Server is starting up shortly, please wait." : "Integruotas CODE serveris netrukus bus paleistas, palaukite.", + "Built-in CODE Server is restarting, please wait." : "Integruotas CODE serveris paleidžiamas iš naujo, palaukite.", + "Error: Cannot find the AppImage, please reinstall the Collabora Online Built-in server." : "Klaida: Negaliu rasti „AppImage“, iš naujo įdiekite integruotą „Collabora Online“ serverį.", + "Error: Unable to make the AppImage executable, please setup a standalone server." : "Klaida: Nepavyko paleisti „AppImage“, nustatykite atskirą serverį.", + "Error: Exec disabled in PHP, please enable it, or setup a standalone server." : "Klaida: PHP funkcija „exec“ išjungta. Įjunkite ją arba sukonfigūruokite atskirą serverį.", + "Error: Not running on x86-64 or ARM64 (aarch64) Linux, please setup a standalone server." : "Klaida: Sistema neveikia „Linux“ aplinkoje su „x86-64“ arba „ARM64“ (aarch64) architektūra. Prašome įdiegti atskirą serverį.", + "Error: The fontconfig library is not installed on your server, please install it or setup a standalone server." : "Klaida: jūsų serveryje neįdiegta „fontconfig“ biblioteka. Įdiekite ją arba sukonfigūruokite atskirą serverį.", + "Error: Not running on glibc-based Linux, please setup a standalone server." : "Klaida: neveikia „Linux“ sistemoje, pagrįstoje „glibc“ biblioteka. Prašome įdiegti atskirą serverį.", + "Error: Cannot start the Collabora Online Built-in server, please setup a standalone one." : "Klaida: Nepavyksta paleisti „Collabora Online“ integruoto serverio. Įdiekite atskirą serverį.", "Close version preview" : "Užverti versijos peržiūrą", "Edit with {productName}" : "Taisyti naudojant {productName}", + "Insert into document" : "Įterpti į dokumentą", "Open file locally" : "Atidaryti failą vietoje", + "When opening a file locally, the document will close for all users currently viewing the document." : "Atidarant failą lokaliai, dokumentas bus uždarytas visiems vartotojams, šiuo metu jį peržiūrintiems.", "Open locally" : "Atidaryti vietoje", + "Continue editing online" : "Tęsti redagavimą internete", + "The file should now open locally. If you don't see this happening, make sure that the desktop client is installed on your system." : "Failas dabar turėtų atsidaryti lokaliai. Jei nematote, kad tai įvyktų, įsitikinkite, kad jūsų sistemoje įdiegta darbalaukio programa.", + "Retry to open locally" : "Pabandykite atidaryti lokaliai", + "Save a copy of the file under a new name and continue editing the new file" : "Išsaugoti failo kopiją nauju pavadinimu ir tęsti naujo failo redagavimą", "Failed to revert the document to older version" : "Nepavyko sugrąžinti dokumentą į senesnę versiją", + "Built-in CODE server failed to start" : "Nepavyko paleisti integruoto CODE serverio", "Insert file from {name}" : "Įterpti failą iš {name}", "Insert file" : "Įterpti failą", "Remove from favorites" : "Pašalinti iš mėgstamų", @@ -165,19 +274,34 @@ "(read only)" : "(tik skaitymui)", "Remove user" : "Šalinti naudotoją", "Guest" : "Svečias", + "Follow current editor" : "Sekite dabartinį redaktorių", "New file" : "Naujas failas", + "Please enter the filename for the new file" : "Įveskite naujo failo pavadinimą", "Saved with error: Collabora Online should use the same protocol as the server installation." : "Įrašyta su klaida: Collabora Online turėtų naudoti tokį patį protokolą kaip ir serverio diegimas.", + "Could not establish connection to the Collabora Online server. This might be due to a missing configuration of your web server. For more information, please visit: " : "Nepavyko užmegzti ryšio su „Collabora Online“ serveriu. Tai gali būti susiję su netinkamai sukonfigūruotu jūsų žiniatinklio serveriu. Daugiau informacijos rasite: ", + "Nextcloud Office requires a seperate server running Collabora Online to provide editing capabilities." : "„Nextcloud Office“ redagavimo galimybėms užtikrinti reikalingas atskiras serveris, kuriame veikia „Collabora Online“.", + "Collabora Online requires a seperate server acting as a WOPI-like Client to provide editing capabilities." : "„Collabora Online“ redagavimo galimybėms užtikrinti reikalingas atskiras serveris, veikiantis kaip WOPI tipo klientas.", + "All users can edit documents with {productName} by default. When this setting is active, only the members of the specified groups can edit and the others can only view documents." : "Pagal numatytuosius nustatymus visi vartotojai gali redaguoti dokumentus su {productName}. Kai šis nustatymas aktyvus, dokumentus gali redaguoti tik nurodytų grupių nariai, o kiti – tik peržiūrėti.", "Secure view settings" : "Saugaus rodinio nustatymai", "Secure view enables you to secure documents by embedding a watermark" : "Saugusis rodinys leidžia jums apsaugoti dokumentus įterpiant vandenženklį", "Enable watermarking" : "Įjungti vandenženklių darymą", "Show watermark on tagged files" : "Rodyti vandenženklį ant failų, turinčių žymas", + "Show watermark for users of groups" : "Rodyti vandenženklį grupių naudotojams", + "Show watermark for all shares" : "Rodyti vandenženklį visose dalinimosi nuorodose", + "Show watermark for read only shares" : "Rodyti vandenženklį bendrinimams, skirtiems tik skaitymui", + "Show watermark for all link shares" : "Rodyti vandens ženklą visiems nuorodų bendrinimams", + "Show watermark for download hidden shares" : "Rodyti vandenženklį bendrinimams su paslėptu atsisiuntimu", + "Show watermark for read only link shares" : "Rodyti vandenženklį tik skaitymo nuorodų bendrinimams", + "Show watermark on link shares with specific system tags" : "Rodyti vandenženklį bendrinamose nuorodose su konkrečiomis sistemos žymėmis", "Error" : "Klaida", "An error occurred" : "Įvyko klaida", "Please choose your nickname to continue as guest user." : "Norėdami tęsti kaip svečias, pasirinkite savo slapyvardį.", "Nickname" : "Slapyvardis", "Set" : "Nustatyti", - "Please enter the filename to store the document as." : "Įveskite naują pavadinimą, kuriuo bus saugomas dokumentas.", + "Please enter the filename to store the document as." : "Įveskite failo pavadinimą, kuriuo bus saugomas dokumentas.", "New filename" : "Naujas failo pavadinimas", + "Collabora Online is not setup yet. Please contact your administrator." : "„Collabora Online“ dar nėra sukonfigūruota. Kreipkitės į savo administratorių.", + "Opening the file is not supported, since the credentials for the external storage are not available without a session" : "Failo atidarymas nepalaikomas, nes be sesijos nėra prieigos duomenų prie išorinės saugyklos", "Failed to connect to {productName}. Please try again later or contact your server administrator." : "Nepavyko prisijungti prie {productName}. Vėliau bandykite dar kartą arba susisiekite su savo serverio administratoriumi.", "Saving…" : "Įrašoma…", "Insert from {name}" : "Įterpti iš {name}", @@ -192,7 +316,13 @@ "No templates defined." : "Neapibrėžtas joks šablonas.", "Add a new one?" : "Pridėti naują?", "template preview" : "šablono peržiūra", + "Files may still be downloadable through Nextcloud unless restricted otherwise through sharing or access control settings" : "Failus vis dar galima atsisiųsti per „Nextcloud“, jei tai nėra apribota bendrinimo ar prieigos kontrolės nustatymuose", + "Previews will be blocked for watermarked files to not leak the first page of documents" : "Failų su vandenženkliu peržiūra bus užblokuota, kad nebūtų atskleista dokumentų pirmoji puslapis", + "Show watermark for shares without download permission" : "Rodyti vandenženklį dalinamiesiems failams, kurių negalima atsisiųsti", + "New drawing" : "Naujas piešinys", "Collabora Online" : "Collabora Online", - "Document already exists" : "Dokumentas jau yra" + "Document already exists" : "Dokumentas jau yra", + "Collabora Online is enabled for all users by default. When this setting is active, only members of the specified groups can use it." : "„Collabora Online“ funkcija visiems vartotojams įjungta pagal numatytuosius nustatymus. Kai šis nustatymas aktyvus, ja gali naudotis tik nurodytų grupių nariai.", + "Templates inside of this directory will be added to the template selector of Collabora Online." : "Šiame kataloge esantys šablonai bus įtraukti į „Collabora Online“ šablonų pasirinkimo sąrašą." },"pluralForm" :"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);" } \ No newline at end of file diff --git a/lib/Controller/OverviewController.php b/lib/Controller/OverviewController.php new file mode 100644 index 0000000000..a6d1e14708 --- /dev/null +++ b/lib/Controller/OverviewController.php @@ -0,0 +1,54 @@ +initialState->provideInitialState('previewEnabled', $this->preview->isMimeSupported('application/vnd.oasis.opendocument.text')); + + // Viewer is pre-installed in production but may not be available in other environments + if (class_exists(LoadViewer::class)) { + $this->eventDispatcher->dispatchTyped(new LoadViewer()); + } + + return new TemplateResponse('richdocuments', 'overview', [ + 'id-app-content' => '#app-content-vue', + 'id-app-navigation' => '#app-navigation-vue', + ]); + } +} diff --git a/lib/Controller/SettingsController.php b/lib/Controller/SettingsController.php index 35f1472ba0..d633f192ae 100644 --- a/lib/Controller/SettingsController.php +++ b/lib/Controller/SettingsController.php @@ -8,6 +8,7 @@ use OCA\Richdocuments\AppConfig; use OCA\Richdocuments\Capabilities; +use OCA\Richdocuments\Db\Wopi; use OCA\Richdocuments\Db\WopiMapper; use OCA\Richdocuments\Service\CapabilitiesService; use OCA\Richdocuments\Service\ConnectivityService; @@ -490,6 +491,9 @@ public function uploadFontFile(): JSONResponse { public function getSettingsFile(string $type, string $token, string $category, string $name) { try { $wopi = $this->wopiMapper->getWopiForToken($token); + if ($wopi->getTokenType() !== Wopi::TOKEN_TYPE_SETTING_AUTH) { + throw new NotPermittedException(); + } $userId = $wopi->getEditorUid() ?: $wopi->getOwnerUid(); if ($type === 'userconfig') { $type = $type . '/' . $userId; @@ -511,6 +515,8 @@ public function getSettingsFile(string $type, string $token, string $category, s 'Content-Type' => $systemFile->getMimeType() ?: 'application/octet-stream' ] ); + } catch (NotPermittedException $e) { + return new DataDisplayResponse('Forbidden.', Http::STATUS_FORBIDDEN); } catch (NotFoundException $e) { return new DataDisplayResponse('File not found.', 404); } catch (\Exception $e) { diff --git a/lib/Controller/WopiController.php b/lib/Controller/WopiController.php index 8f9593d892..207b2d423e 100644 --- a/lib/Controller/WopiController.php +++ b/lib/Controller/WopiController.php @@ -21,6 +21,7 @@ use OCA\Richdocuments\Service\FederationService; use OCA\Richdocuments\Service\SettingsService; use OCA\Richdocuments\Service\UserScopeService; +use OCA\Richdocuments\Service\WopiRateLimitService; use OCA\Richdocuments\TaskProcessingManager; use OCA\Richdocuments\TemplateManager; use OCA\Richdocuments\TokenManager; @@ -59,6 +60,7 @@ use OCP\IUserManager; use OCP\Lock\LockedException; use OCP\PreConditionNotMetException; +use OCP\Security\RateLimiting\IRateLimitExceededException; use OCP\Share\Exceptions\ShareNotFound; use OCP\Share\IManager as IShareManager; use OCP\Share\IShare; @@ -97,6 +99,7 @@ public function __construct( private SettingsService $settingsService, private CapabilitiesService $capabilitiesService, private Helper $helper, + private WopiRateLimitService $wopiRateLimitService, ) { parent::__construct($appName, $request); } @@ -132,11 +135,35 @@ public function checkFileInfo( return new JSONResponse([], Http::STATUS_FORBIDDEN); } + if ($wopi->isGuest()) { + try { + $this->wopiRateLimitService->registerRequest($wopi, 'checkFileInfo'); + } catch (IRateLimitExceededException $e) { + $this->logger->warning('WOPI checkFileInfo rate limit exceeded for token {wopiId} from {remoteAddress}', [ + 'wopiId' => $wopi->getId(), + 'remoteAddress' => $this->request->getRemoteAddress(), + ]); + return new JSONResponse([], Http::STATUS_TOO_MANY_REQUESTS); + } + } + $isPublic = empty($wopi->getEditorUid()); + $isVersion = $version !== '0'; + if ($isPublic && $isVersion) { + $this->logger->debug( + 'Version access with public link is not allowed', + [ + 'fileId' => $fileId, + 'version' => $version + ], + ); + + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + $guestUserId = 'Guest-' . \OCP\Server::get(\OCP\Security\ISecureRandom::class)->generate(8); $user = $this->userManager->get($wopi->getEditorUid()); $userDisplayName = $user !== null && !$isPublic ? $user->getDisplayName() : $wopi->getGuestDisplayname(); - $isVersion = $version !== '0'; $isSmartPickerEnabled = (bool)$wopi->getCanwrite() && !$isPublic && !$wopi->getDirect(); $isTaskProcessingEnabled = $isSmartPickerEnabled && $this->taskProcessingManager->isTaskProcessingEnabled(); @@ -353,6 +380,18 @@ public function getFile( return new JSONResponse([], Http::STATUS_FORBIDDEN); } + if ($wopi->isGuest()) { + try { + $this->wopiRateLimitService->registerRequest($wopi, 'getFile'); + } catch (IRateLimitExceededException $e) { + $this->logger->warning('WOPI getFile rate limit exceeded for token {wopiId} from {remoteAddress}', [ + 'wopiId' => $wopi->getId(), + 'remoteAddress' => $this->request->getRemoteAddress(), + ]); + return new JSONResponse([], Http::STATUS_TOO_MANY_REQUESTS); + } + } + if ((int)$fileId !== $wopi->getFileid()) { return new JSONResponse([], Http::STATUS_FORBIDDEN); } @@ -362,6 +401,18 @@ public function getFile( $file = $this->getFileForWopiToken($wopi); \OC_User::setIncognitoMode(true); if ($version !== '0') { + if (empty($wopi->getEditorUid())) { + $this->logger->debug( + 'Version access with public link is not allowed', + [ + 'fileId' => $fileId, + 'version' => $version + ], + ); + + return new JSONResponse([], Http::STATUS_FORBIDDEN); + } + $versionManager = \OCP\Server::get(IVersionManager::class); $info = $versionManager->getVersionFile($this->userManager->get($wopi->getUserForFileAccess()), $file, $version); if ($info->getSize() === 0) { @@ -546,10 +597,10 @@ public function deleteSettingsFile( } } - /** - * Given an access token and a fileId, replaces the files with the request body. - * Expects a valid token in access_token parameter. + * Implements WOPI File contents operation `PutFile`. + * + * https://learn.microsoft.com/en-us/microsoft-365/cloud-storage-partner-program/rest/files/putfile */ #[NoAdminRequired] #[NoCSRFRequired] @@ -561,7 +612,6 @@ public function putFile( string $access_token, ): JSONResponse { [$fileId, , ] = Helper::parseFileId($fileId); - $isPutRelative = ($this->request->getHeader('X-WOPI-Override') === 'PUT_RELATIVE'); try { $wopi = $this->wopiMapper->getWopiForToken($access_token); @@ -583,7 +633,7 @@ public function putFile( if (!$this->encryptionManager->isEnabled() || $this->isMasterKeyEnabled()) { // Set the user to register the change under his name $this->userScopeService->setUserScope($wopi->getEditorUid()); - $this->userScopeService->setFilesystemScope($isPutRelative ? $wopi->getEditorUid() : $wopi->getUserForFileAccess()); + $this->userScopeService->setFilesystemScope($wopi->getUserForFileAccess()); } else { // Per-user encryption is enabled so that collabora isn't able to store the file by using the // user's private key. Because of that we have to use the incognito mode for writing the file. @@ -591,52 +641,16 @@ public function putFile( } try { - if ($isPutRelative) { - // the new file needs to be installed in the current user dir - $userFolder = $this->rootFolder->getUserFolder($wopi->getEditorUid()); - $file = $userFolder->getFirstNodeById($fileId); - if ($file === null) { - return new JSONResponse([], Http::STATUS_NOT_FOUND); - } - $suggested = $this->request->getHeader('X-WOPI-SuggestedTarget'); - $suggested = (string)mb_convert_encoding($suggested, 'utf-8', 'utf-7'); - - if ($suggested[0] === '.') { - $path = dirname($file->getPath()) . '/New File' . $suggested; - } elseif ($suggested[0] !== '/') { - $path = dirname($file->getPath()) . '/' . $suggested; - } else { - $path = $userFolder->getPath() . $suggested; - } - - if ($path === '') { - return new JSONResponse([ - 'status' => 'error', - 'message' => 'Cannot create the file' - ]); - } - - // create the folder first - if (!$this->rootFolder->nodeExists(dirname($path))) { - $this->rootFolder->newFolder(dirname($path)); - } - - // create a unique new file - $path = $this->rootFolder->getNonExistingName($path); - $this->rootFolder->newFile($path); - $file = $this->rootFolder->get($path); - } else { - $file = $this->getFileForWopiToken($wopi); - $wopiHeaderTime = $this->request->getHeader('X-COOL-WOPI-Timestamp'); - - if (!empty($wopiHeaderTime) && $wopiHeaderTime !== Helper::toISO8601($file->getMTime() ?? 0)) { - $this->logger->debug('Document timestamp mismatch ! WOPI client says mtime {headerTime} but storage says {storageTime}', [ - 'headerTime' => $wopiHeaderTime, - 'storageTime' => Helper::toISO8601($file->getMTime() ?? 0) - ]); - // Tell WOPI client about this conflict. - return new JSONResponse(['COOLStatusCode' => self::COOL_STATUS_DOC_CHANGED], Http::STATUS_CONFLICT); - } + $file = $this->getFileForWopiToken($wopi); + $wopiHeaderTime = $this->request->getHeader('X-COOL-WOPI-Timestamp'); + + if (!empty($wopiHeaderTime) && $wopiHeaderTime !== Helper::toISO8601($file->getMTime() ?? 0)) { + $this->logger->debug('Document timestamp mismatch ! WOPI client says mtime {headerTime} but storage says {storageTime}', [ + 'headerTime' => $wopiHeaderTime, + 'storageTime' => Helper::toISO8601($file->getMTime() ?? 0) + ]); + // Tell WOPI client about this conflict. + return new JSONResponse(['COOLStatusCode' => self::COOL_STATUS_DOC_CHANGED], Http::STATUS_CONFLICT); } $content = fopen('php://input', 'rb'); @@ -654,11 +668,6 @@ public function putFile( return new JSONResponse(['message' => 'File locked'], Http::STATUS_INTERNAL_SERVER_ERROR); } - if ($isPutRelative) { - // generate a token for the new file (the user still has to be logged in) - $wopi = $this->tokenManager->generateWopiToken((string)$file->getId(), null, $wopi->getEditorUid(), $wopi->getDirect()); - return new JSONResponse(['Name' => $file->getName(), 'Url' => $this->getWopiUrlForFile($wopi, $file)], Http::STATUS_OK); - } if ($wopi->hasTemplateId()) { $wopi->setTemplateId(null); $this->wopiMapper->update($wopi); diff --git a/lib/Middleware/WOPIMiddleware.php b/lib/Middleware/WOPIMiddleware.php index 54cb0e328f..66f9636599 100644 --- a/lib/Middleware/WOPIMiddleware.php +++ b/lib/Middleware/WOPIMiddleware.php @@ -88,7 +88,8 @@ public function beforeController($controller, $methodName) { if ($hasProofKey) { $wopiTimestamp = $this->request->getHeader('X-WOPI-TimeStamp'); - $wopiTimestampIsOld = $this->proofKeyService->isOldTimestamp((int)$wopiTimestamp); + $unixTimestamp = $this->proofKeyService->ticksToUnixTimestamp((int)$wopiTimestamp); + $wopiTimestampIsOld = $this->proofKeyService->isOldTimestamp($unixTimestamp); if ($wopiTimestampIsOld) { throw new WopiException('X-WOPI-TimeStamp header is older than 20 minutes'); diff --git a/lib/Service/CachedRequestService.php b/lib/Service/CachedRequestService.php index 7ddc5ab196..319578e120 100644 --- a/lib/Service/CachedRequestService.php +++ b/lib/Service/CachedRequestService.php @@ -114,44 +114,75 @@ private function getAppDataFolder(): ISimpleFolder { } /** - * @return boolean indicating if proxy.php is in initialize or false otherwise + * Checks if the Collabora proxy (i.e. built-in CODE app) is in-use and, if so, whether it is currently + * initializing ("starting" or "restarting"). + * + * @return bool True if proxy is initializing; false otherwise. */ private function isProxyStarting(): bool { $url = $this->appConfig->getValueString('richdocuments', 'wopi_url', ''); - $usesProxy = false; $proxyPos = strrpos($url, 'proxy.php'); - if ($proxyPos !== false) { - $usesProxy = true; + + if ($proxyPos === false) { + return false; } - if ($usesProxy === true) { - $statusUrl = substr($url, 0, $proxyPos); - $statusUrl = $statusUrl . 'proxy.php?status'; + // Build endpoint for status checking + $statusUrl = substr($url, 0, $proxyPos) . 'proxy.php?status'; + + $options = [ + 'timeout' => 5, + 'nextcloud' => ['allow_local_address' => true] + ]; + + if ($this->appConfig->getValueString('richdocuments', 'disable_certificate_verification') === 'yes') { + $options['verify'] = false; + } + try { $client = $this->clientService->newClient(); - $options = ['timeout' => 5, 'nextcloud' => ['allow_local_address' => true]]; + $response = $client->get($statusUrl, $options); - if ($this->appConfig->getValueString('richdocuments', 'disable_certificate_verification') === 'yes') { - $options['verify'] = false; + $statusCode = $response->getStatusCode(); + + if ($statusCode !== 200) { + $this->logger->debug("isProxyStarting: Proxy status endpoint returned non-200 code: {$statusCode} url={$statusUrl}"); + return false; } - try { - $response = $client->get($statusUrl, $options); + $bodyRaw = $response->getBody(); + $body = json_decode($bodyRaw, true); - if ($response->getStatusCode() === 200) { - $body = json_decode($response->getBody(), true); + if (!is_array($body) || !isset($body['status'])) { + $this->logger->debug("isProxyStarting: Unexpected response format from proxy: url={$statusUrl} body={$bodyRaw}"); + return false; + } - if ($body['status'] === 'starting' - || $body['status'] === 'stopped' - || $body['status'] === 'restarting') { - return true; - } - } - } catch (\Exception) { - // ignore + if ($body['status'] === 'error') { + $errorDetail = $body['error'] ?? ''; + $this->logger->error("isProxyStarting: Proxy returned status 'error'. url={$statusUrl} error=\"{$errorDetail}\""); + return false; + } + + if ($body['status'] === 'OK') { + $this->logger->debug("isProxyStarting: Proxy status is OK at url={$statusUrl} (already started)"); + return false; + } + + if ($body['status'] === 'starting' || $body['status'] === 'restarting') { + $this->logger->debug("isProxyStarting: Proxy is '{$body['status']}' at url={$statusUrl}"); + return true; } - } - return false; + // Defensive fallback + $this->logger->debug("isProxyStarting: Proxy status is '{$body['status']}' at url={$statusUrl} (not starting)"); + return false; + } catch (\Throwable $e) { + $this->logger->debug( + "isProxyStarting: Exception contacting proxy status endpoint at {$statusUrl}: {$e->getMessage()}", + ['exception' => $e] + ); + return false; + } } } diff --git a/lib/Service/ProofKeyService.php b/lib/Service/ProofKeyService.php index b58bbdde2b..e76c345944 100644 --- a/lib/Service/ProofKeyService.php +++ b/lib/Service/ProofKeyService.php @@ -17,11 +17,10 @@ use Throwable; class ProofKeyService { - // The Windows epoch is used for WOPI timestamps (as it is a MS protocol) - // Notes: According to the MS documentation it begins on 01-01-0001 - // but all evidence in practice points to 01-01-1601 - private const WINDOWS_EPOCH = '01-01-1601 00:00:00'; - private const UNIX_EPOCH = '01-01-1970 00:00:00'; + // Offset between the .NET epoch (01-01-0001 00:00:00 UTC) + // and the Unix epoch (01-01-1970 00:00:00 UTC) + // in 100-nanosecond intervals + private const EPOCH_OFFSET = 621355968000000000; public function __construct( private DiscoveryService $discoveryService, @@ -48,27 +47,20 @@ public function isProofValid(string $accessToken, string $url, string $wopiTimes return $isValid; } - public function windowsToUnixTimestamp(string $windowsTimestamp): string { - // Convert the epochs to timestamps - $windowsEpoch = strtotime(self::WINDOWS_EPOCH); - $unixEpoch = strtotime(self::UNIX_EPOCH); + public function ticksToUnixTimestamp(int $ticks): int { + // Subtract the epoch offset from the .NET ticks + $unixTicks = $ticks - self::EPOCH_OFFSET; - // Calculate the difference between the Unix and Windows epochs in seconds - $epochOffset = (float)($unixEpoch - $windowsEpoch); + // Divide that by 1e7 to convert from 100ns intervals to seconds + $unixTimestamp = intdiv($unixTicks, 10000000); - // Convert the Windows timestamp from 100-nanoseconds intervals to seconds - $windowsTimestampSeconds = ((float)$windowsTimestamp) / 1e7; - - // Finally, subtract the number of seconds between the Windows and Unix epochs - // from the number of seconds in the given Windows timestamp - $convertedWindowsTimestamp = (int)($windowsTimestampSeconds - $epochOffset); - - return (string)$convertedWindowsTimestamp; + // That leaves us with the Unix timestamp + return $unixTimestamp; } - public function isOldTimestamp(int $timestamp): bool { + public function isOldTimestamp(int $unixTimestamp): bool { $timestampDateTime = new DateTime(); - $timestampDateTime->setTimestamp($timestamp); + $timestampDateTime->setTimestamp($unixTimestamp); $now = new DateTimeImmutable(); $controlDateTime = $now->modify('-20 minutes'); diff --git a/lib/Service/RemoteService.php b/lib/Service/RemoteService.php index 60776e614e..479910331d 100644 --- a/lib/Service/RemoteService.php +++ b/lib/Service/RemoteService.php @@ -101,7 +101,7 @@ public function convertTo(string $filename, $stream, string $format, ?array $con return $body; } catch (\Exception $e) { - $this->logger->error('Failed to convert preview: ' . $e->getMessage(), ['exception' => $e]); + $this->logger->info('Failed to convert preview: ' . $e->getMessage(), ['exception' => $e]); throw $e; } } diff --git a/lib/Service/WopiRateLimitService.php b/lib/Service/WopiRateLimitService.php new file mode 100644 index 0000000000..77e2720923 --- /dev/null +++ b/lib/Service/WopiRateLimitService.php @@ -0,0 +1,33 @@ +limiter->registerAnonRequest( + 'richdocuments::wopi::' . $action . '::' . $wopi->getId(), + 10, + 120, + $this->request->getRemoteAddress() + ); + } +} diff --git a/package-lock.json b/package-lock.json index c7ecefac28..2b1cd2cef0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "richdocuments", - "version": "11.0.0-dev.0", + "version": "12.0.0-dev.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "richdocuments", - "version": "11.0.0-dev.0", + "version": "12.0.0-dev.0", "license": "AGPL-3.0-or-later", "dependencies": { "@nextcloud/auth": "^2.6.0", @@ -37,7 +37,7 @@ "@nextcloud/stylelint-config": "^3.2.1", "@nextcloud/webpack-vue-config": "^7.0.2", "babel-loader-exclude-node-modules-except": "^1.2.4", - "cypress": "^15.14.1", + "cypress": "^15.14.2", "cypress-split": "^1.24.31", "eslint-plugin-cypress": "^3.5.0", "ts-loader": "^9.5.7", @@ -372,14 +372,15 @@ } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1173,16 +1174,16 @@ } }, "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz", + "integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "@babel/traverse": "^7.29.0" }, "engines": { "node": ">=6.9.0" @@ -4469,9 +4470,9 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", "dev": true, "license": "BSD-3-Clause" }, @@ -4501,9 +4502,9 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", + "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", "dev": true, "license": "BSD-3-Clause" }, @@ -4522,9 +4523,9 @@ "license": "BSD-3-Clause" }, "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", "dev": true, "license": "BSD-3-Clause" }, @@ -5864,19 +5865,6 @@ "node": ">=0.4.0" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -5933,37 +5921,17 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "dev": true, + "license": "MIT", "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" + "environment": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -6213,6 +6181,7 @@ "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", "dev": true, + "peer": true, "engines": { "node": ">=8" } @@ -7465,25 +7434,20 @@ "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==" }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, + "license": "MIT", "dependencies": { - "restore-cursor": "^3.1.0" + "restore-cursor": "^5.0.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-table3": { @@ -7503,33 +7467,112 @@ } }, "node_modules/cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", "dev": true, + "license": "MIT", "dependencies": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cli-truncate/node_modules/slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/cli-truncate/node_modules/string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-truncate/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/cliui": { @@ -7640,10 +7683,11 @@ "peer": true }, "node_modules/colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", - "dev": true + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.4.0", @@ -8243,9 +8287,9 @@ "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "node_modules/cypress": { - "version": "15.14.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.14.1.tgz", - "integrity": "sha512-AkuiHNSnmm0a+h/horcvbjmY6dWpCe1Ebp1R0LjMP5I6pjMaNA50Mw1YP/d07pLHJ/sV8FZoGecUWFCJ/Nifpw==", + "version": "15.14.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.14.2.tgz", + "integrity": "sha512-xMWg/iEImeIThRQZdnf3BFJT1a84apM/R91Feoa4vVWGuYWDphMT5jLhRVTBVlCgi+6axegF1zqhNyjhug2SsQ==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -8259,25 +8303,22 @@ "blob-util": "^2.0.2", "bluebird": "^3.7.2", "buffer": "^5.7.1", - "cachedir": "^2.3.0", + "cachedir": "^2.4.0", "chalk": "^4.1.0", "ci-info": "^4.1.0", - "cli-cursor": "^3.1.0", "cli-table3": "0.6.1", "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", "debug": "^4.3.4", - "enquirer": "^2.3.6", "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", - "figures": "^3.2.0", "fs-extra": "^9.1.0", "hasha": "5.2.2", "is-installed-globally": "~0.4.0", - "listr2": "^3.8.3", + "listr2": "^9.0.5", "lodash": "^4.17.23", "log-symbols": "^4.0.0", "minimist": "^1.2.8", @@ -9510,19 +9551,6 @@ "node": ">=10.13.0" } }, - "node_modules/enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8.6" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -9562,6 +9590,19 @@ "node": ">=4" } }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -9776,15 +9817,6 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/escodegen": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", @@ -10864,9 +10896,9 @@ } }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "funding": [ { @@ -10882,9 +10914,9 @@ "peer": true }, "node_modules/fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "funding": [ { "type": "github", @@ -10893,7 +10925,8 @@ ], "license": "MIT", "dependencies": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "node_modules/fast-xml-parser": { @@ -10980,21 +11013,6 @@ "node": "^12.20 || >= 14.13" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -11497,7 +11515,6 @@ "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -12448,15 +12465,6 @@ "node": ">=0.8.19" } }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -13550,30 +13558,113 @@ "peer": true }, "node_modules/listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "dependencies": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "license": "MIT", + "dependencies": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=10.0.0" + "node": ">=20.0.0" + } + }, + "node_modules/listr2/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, - "peerDependencies": { - "enquirer": ">= 2.3.0 < 3" + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" }, - "peerDependenciesMeta": { - "enquirer": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/listr2/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/loader-runner": { @@ -13709,35 +13800,141 @@ } }, "node_modules/log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-update/node_modules/is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, + "engines": { + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log-update/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/log-update/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/long": { @@ -14636,6 +14833,19 @@ "node": ">=6" } }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -15253,21 +15463,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/p-queue": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", @@ -15460,9 +15655,9 @@ } }, "node_modules/path-expression-matcher": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.4.0.tgz", - "integrity": "sha512-s4DQMxIdhj3jLFWd9LxHOplj4p9yQ4ffMGowFf3cpEgrrJjEhN0V5nxw4Ye1EViAGDoL4/1AeO6qHpqYPOzE4Q==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==", "funding": [ { "type": "github", @@ -16068,23 +16263,23 @@ } }, "node_modules/protobufjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", - "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.8.tgz", + "integrity": "sha512-dvpCIeLPbXZS/Ete7yLaO7RenOdken2NHKykBXbsaGxZT0UTltcarBciw+A78SRQs9iMAAVpsYA+l8b1hTePIA==", "dev": true, "hasInstallScript": true, "license": "BSD-3-Clause", "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", + "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", + "@protobufjs/inquire": "^1.1.1", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.0.0" }, @@ -17064,16 +17259,49 @@ } }, "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, + "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/retry": { @@ -17098,10 +17326,11 @@ } }, "node_modules/rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", - "dev": true + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", + "dev": true, + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", @@ -17899,6 +18128,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -19096,9 +19326,9 @@ } }, "node_modules/systeminformation": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.1.tgz", - "integrity": "sha512-6pRwxoGeV/roJYpsfcP6tN9mep6pPeCtXbUOCdVa0nme05Brwcwdge/fVNhIZn2wuUitAKZm4IYa7QjnRIa9zA==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.6.tgz", + "integrity": "sha512-Uv2b2uGGM6ns+26czgW2cYRabYdnswM0ddSOOlryHOaelzsmDSet1iM/NT7VOYxW8x/BW+HkY+b1Ve2pLTSGSA==", "dev": true, "license": "MIT", "os": [ @@ -21455,6 +21685,21 @@ "node": ">=12" } }, + "node_modules/xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -21785,14 +22030,14 @@ } }, "@babel/helper-module-transforms": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz", - "integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1", - "@babel/traverse": "^7.28.3" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" } }, "@babel/helper-optimise-call-expression": { @@ -22269,15 +22514,15 @@ } }, "@babel/plugin-transform-modules-systemjs": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz", - "integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==", + "version": "7.29.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.29.4.tgz", + "integrity": "sha512-N7QmZ0xRZfjHOfZeQLJjwgX2zS9pdGHSVl/cjSGlo4dXMqvurfxXDMKY4RqEKzPozV78VMcd0lxyG13mlbKc4w==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.28.3", - "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.5" + "@babel/traverse": "^7.29.0" } }, "@babel/plugin-transform-modules-umd": { @@ -24283,9 +24528,9 @@ "dev": true }, "@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", "dev": true }, "@protobufjs/eventemitter": { @@ -24311,9 +24556,9 @@ "dev": true }, "@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.1.tgz", + "integrity": "sha512-mnzgDV26ueAvk7rsbt9L7bE0SuAoqyuys/sMMrmVcN5x9VsxpcG3rqAUSgDyLp0UZlmNfIbQ4fHfCtreVBk8Ew==", "dev": true }, "@protobufjs/path": { @@ -24329,9 +24574,9 @@ "dev": true }, "@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.1.tgz", + "integrity": "sha512-oOAWABowe8EAbMyWKM0tYDKi8Yaox52D+HWZhAIJqQXbqe0xI/GV7FhLWqlEKreMkfDjshR5FKgi3mnle0h6Eg==", "dev": true }, "@sindresorhus/merge-streams": { @@ -25321,16 +25566,6 @@ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", "dev": true }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -25373,27 +25608,13 @@ } } }, - "ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true - }, "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", "dev": true, "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } + "environment": "^1.0.0" } }, "ansi-html-community": { @@ -25568,7 +25789,8 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true + "dev": true, + "peer": true }, "asynckit": { "version": "0.4.0", @@ -26506,19 +26728,13 @@ "resolved": "https://registry.npmjs.org/clamp/-/clamp-1.0.1.tgz", "integrity": "sha512-kgMuFyE78OC6Dyu3Dy7vcx4uy97EIbVxJB/B0eJ3bUNAkwdNcxYzgKltnyADiYwsR7SEqkkUPsEUT//OVS6XMA==" }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", "dev": true, "requires": { - "restore-cursor": "^3.1.0" + "restore-cursor": "^5.0.0" } }, "cli-table3": { @@ -26532,24 +26748,63 @@ } }, "cli-truncate": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", - "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz", + "integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==", "dev": true, "requires": { - "slice-ansi": "^3.0.0", - "string-width": "^4.2.0" + "slice-ansi": "^8.0.0", + "string-width": "^8.2.0" }, "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "requires": { + "get-east-asian-width": "^1.3.1" + } + }, "slice-ansi": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", - "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", + "integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==", + "dev": true, + "requires": { + "ansi-styles": "^6.2.3", + "is-fullwidth-code-point": "^5.1.0" + } + }, + "string-width": { + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, + "requires": { + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" + } + }, + "strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "ansi-regex": "^6.2.2" } } } @@ -26633,9 +26888,9 @@ "peer": true }, "colorette": { - "version": "2.0.19", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz", - "integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==", + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", "dev": true }, "colors": { @@ -27077,9 +27332,9 @@ "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" }, "cypress": { - "version": "15.14.1", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.14.1.tgz", - "integrity": "sha512-AkuiHNSnmm0a+h/horcvbjmY6dWpCe1Ebp1R0LjMP5I6pjMaNA50Mw1YP/d07pLHJ/sV8FZoGecUWFCJ/Nifpw==", + "version": "15.14.2", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-15.14.2.tgz", + "integrity": "sha512-xMWg/iEImeIThRQZdnf3BFJT1a84apM/R91Feoa4vVWGuYWDphMT5jLhRVTBVlCgi+6axegF1zqhNyjhug2SsQ==", "dev": true, "requires": { "@cypress/request": "^3.0.10", @@ -27091,25 +27346,22 @@ "blob-util": "^2.0.2", "bluebird": "^3.7.2", "buffer": "^5.7.1", - "cachedir": "^2.3.0", + "cachedir": "^2.4.0", "chalk": "^4.1.0", "ci-info": "^4.1.0", - "cli-cursor": "^3.1.0", "cli-table3": "0.6.1", "commander": "^6.2.1", "common-tags": "^1.8.0", "dayjs": "^1.10.4", "debug": "^4.3.4", - "enquirer": "^2.3.6", "eventemitter2": "6.4.7", "execa": "4.1.0", "executable": "^4.1.1", "extract-zip": "2.0.1", - "figures": "^3.2.0", "fs-extra": "^9.1.0", "hasha": "5.2.2", "is-installed-globally": "~0.4.0", - "listr2": "^3.8.3", + "listr2": "^9.0.5", "lodash": "^4.17.23", "log-symbols": "^4.0.0", "minimist": "^1.2.8", @@ -27983,16 +28235,6 @@ "tapable": "^2.3.0" } }, - "enquirer": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", - "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1", - "strip-ansi": "^6.0.1" - } - }, "entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -28014,6 +28256,12 @@ "dev": true, "peer": true }, + "environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true + }, "error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -28184,12 +28432,6 @@ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, "escodegen": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", @@ -28960,18 +29202,19 @@ } }, "fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "dev": true, "peer": true }, "fast-xml-builder": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz", - "integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz", + "integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==", "requires": { - "path-expression-matcher": "^1.1.3" + "path-expression-matcher": "^1.5.0", + "xml-naming": "^0.1.0" } }, "fast-xml-parser": { @@ -29028,15 +29271,6 @@ "web-streams-polyfill": "^3.0.3" } }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - } - }, "file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -29393,8 +29627,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", - "dev": true, - "peer": true + "dev": true }, "get-intrinsic": { "version": "1.3.0", @@ -30065,12 +30298,6 @@ "dev": true, "peer": true }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -30819,19 +31046,74 @@ "peer": true }, "listr2": { - "version": "3.14.0", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", - "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", - "dev": true, - "requires": { - "cli-truncate": "^2.1.0", - "colorette": "^2.0.16", - "log-update": "^4.0.0", - "p-map": "^4.0.0", - "rfdc": "^1.3.0", - "rxjs": "^7.5.1", - "through": "^2.3.8", - "wrap-ansi": "^7.0.0" + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", + "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "dev": true, + "requires": { + "cli-truncate": "^5.0.0", + "colorette": "^2.0.20", + "eventemitter3": "^5.0.1", + "log-update": "^6.1.0", + "rfdc": "^1.4.1", + "wrap-ansi": "^9.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true + }, + "emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true + }, + "eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "dev": true + }, + "string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "requires": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + } + }, + "strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "requires": { + "ansi-regex": "^6.2.2" + } + }, + "wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "requires": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + } + } } }, "loader-runner": { @@ -30939,26 +31221,84 @@ } }, "log-update": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", - "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.1.0.tgz", + "integrity": "sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==", "dev": true, "requires": { - "ansi-escapes": "^4.3.0", - "cli-cursor": "^3.1.0", - "slice-ansi": "^4.0.0", - "wrap-ansi": "^6.2.0" + "ansi-escapes": "^7.0.0", + "cli-cursor": "^5.0.0", + "slice-ansi": "^7.1.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "dependencies": { + "ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true + }, + "emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, + "requires": { + "get-east-asian-width": "^1.3.1" + } + }, + "slice-ansi": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", + "integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==", + "dev": true, + "requires": { + "ansi-styles": "^6.2.1", + "is-fullwidth-code-point": "^5.0.0" + } + }, + "string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "requires": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + } + }, + "strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "requires": { + "ansi-regex": "^6.2.2" + } + }, "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" } } } @@ -31515,6 +31855,12 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true + }, "minimalistic-assert": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", @@ -31959,15 +32305,6 @@ "p-limit": "^3.0.2" } }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.0.0" - } - }, "p-queue": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/p-queue/-/p-queue-8.1.1.tgz", @@ -32098,9 +32435,9 @@ "dev": true }, "path-expression-matcher": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.4.0.tgz", - "integrity": "sha512-s4DQMxIdhj3jLFWd9LxHOplj4p9yQ4ffMGowFf3cpEgrrJjEhN0V5nxw4Ye1EViAGDoL4/1AeO6qHpqYPOzE4Q==" + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz", + "integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==" }, "path-is-absolute": { "version": "1.0.1", @@ -32500,21 +32837,21 @@ "integrity": "sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==" }, "protobufjs": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.5.tgz", - "integrity": "sha512-3wY1AxV+VBNW8Yypfd1yQY9pXnqTAN+KwQxL8iYm3/BjKYMNg4i0owhEe26PWDOMaIrzeeF98Lqd5NGz4omiIg==", + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.5.8.tgz", + "integrity": "sha512-dvpCIeLPbXZS/Ete7yLaO7RenOdken2NHKykBXbsaGxZT0UTltcarBciw+A78SRQs9iMAAVpsYA+l8b1hTePIA==", "dev": true, "requires": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", + "@protobufjs/codegen": "^2.0.5", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", + "@protobufjs/inquire": "^1.1.1", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", "@types/node": ">=13.7.0", "long": "^5.0.0" } @@ -33240,13 +33577,30 @@ "peer": true }, "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", "dev": true, "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "dependencies": { + "onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "requires": { + "mimic-function": "^5.0.0" + } + }, + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true + } } }, "retry": { @@ -33263,9 +33617,9 @@ "dev": true }, "rfdc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", - "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "dev": true }, "rimraf": { @@ -33819,6 +34173,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", "dev": true, + "peer": true, "requires": { "ansi-styles": "^4.0.0", "astral-regex": "^2.0.0", @@ -34641,9 +34996,9 @@ } }, "systeminformation": { - "version": "5.31.1", - "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.1.tgz", - "integrity": "sha512-6pRwxoGeV/roJYpsfcP6tN9mep6pPeCtXbUOCdVa0nme05Brwcwdge/fVNhIZn2wuUitAKZm4IYa7QjnRIa9zA==", + "version": "5.31.6", + "resolved": "https://registry.npmjs.org/systeminformation/-/systeminformation-5.31.6.tgz", + "integrity": "sha512-Uv2b2uGGM6ns+26czgW2cYRabYdnswM0ddSOOlryHOaelzsmDSet1iM/NT7VOYxW8x/BW+HkY+b1Ve2pLTSGSA==", "dev": true }, "tabbable": { @@ -36293,6 +36648,11 @@ "dev": true, "peer": true }, + "xml-naming": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz", + "integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index 1117b78000..acb9767359 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "richdocuments", "description": "Collabora online integration", - "version": "11.0.0-dev.0", + "version": "12.0.0-dev.0", "authors": [ { "name": "Julius Härtl", @@ -59,7 +59,7 @@ "@nextcloud/stylelint-config": "^3.2.1", "@nextcloud/webpack-vue-config": "^7.0.2", "babel-loader-exclude-node-modules-except": "^1.2.4", - "cypress": "^15.14.1", + "cypress": "^15.14.2", "cypress-split": "^1.24.31", "eslint-plugin-cypress": "^3.5.0", "ts-loader": "^9.5.7", diff --git a/src/components/AdminSettings/GlobalTemplates.vue b/src/components/AdminSettings/GlobalTemplates.vue index 5b1a82c7b3..2dbbc389c2 100644 --- a/src/components/AdminSettings/GlobalTemplates.vue +++ b/src/components/AdminSettings/GlobalTemplates.vue @@ -14,37 +14,37 @@ @change="selectFile">
- -
-
- -
- {{ t('richdocuments', 'New') }} -
-
- -
- -
-
-
- -
+ + + + + + + + +
+ + diff --git a/src/overview.js b/src/overview.js new file mode 100644 index 0000000000..2eca428705 --- /dev/null +++ b/src/overview.js @@ -0,0 +1,15 @@ +/** + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +import './init-shared.js' +import '../css/filetypes.scss' +import Vue from 'vue' +import OfficeOverview from './views/OfficeOverview.vue' + +Vue.prototype.t = t +Vue.prototype.n = n + +new Vue({ + render: h => h(OfficeOverview), +}).$mount('#content') diff --git a/src/services/officeFiles.js b/src/services/officeFiles.js new file mode 100644 index 0000000000..fe2a07833d --- /dev/null +++ b/src/services/officeFiles.js @@ -0,0 +1,89 @@ +/** + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { getClient, getDavNameSpaces, getDavProperties, getRootPath, resultToNode } from '@nextcloud/files/dav' + +/** + * Build a DAV SEARCH request body that matches files of any of the given MIME types + * across all subdirectories (depth: infinity). + * + * @param {string[]} mimes List of MIME type strings to search for + * @return {string} XML string for the SEARCH request body + */ +function buildOfficeMimeSearch(mimes) { + const conditions = mimes + .map(mime => `\t\t\t\t${mime}`) + .join('\n') + + return ` + + + + + ${getDavProperties()} + + + + + ${getRootPath()}/ + infinity + + + + +${conditions} + + + +` +} + +/** @type {import('@nextcloud/files').Node[]|null} */ +let cachedNodes = null + +/** + * Fetch all office files matching the given MIME types and cache the result. + * Subsequent calls with the same set of MIMEs return the cached array. + * Pass an empty array to invalidate and re-fetch. + * + * @param {string[]} mimes MIME types to search for, derived from template creators + * @return {Promise} + */ +export async function getAllOfficeFiles(mimes) { + if (cachedNodes) { + return cachedNodes + } + + const client = getClient() + + const response = await client.search('/', { + details: true, + data: buildOfficeMimeSearch(mimes), + }) + + cachedNodes = response.data.results + .map(item => resultToNode(item)) + .filter(node => node.type === 'file') + + return cachedNodes +} + +/** + * Discard the cached file list so the next getAllOfficeFiles() call re-fetches. + */ +export function invalidateOfficeFilesCache() { + cachedNodes = null +} + +/** + * Filter a list of file nodes to those whose MIME type is in the given set. + * + * @param {import('@nextcloud/files').Node[]} files + * @param {string[]} mimes MIME types for the active category + * @return {import('@nextcloud/files').Node[]} + */ +export function filterByMimes(files, mimes) { + return files.filter(file => mimes.includes(file.mime)) +} diff --git a/src/services/templates.js b/src/services/templates.js new file mode 100644 index 0000000000..f11cb68a1d --- /dev/null +++ b/src/services/templates.js @@ -0,0 +1,38 @@ +/** + * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +// Mirrors apps/files/src/services/Templates.js — uses NC core Files API, not richdocuments OCS. + +import axios from '@nextcloud/axios' +import { generateOcsUrl } from '@nextcloud/router' + +/** + * Fetch all template creators registered with the NC Files API. + * Returns an array of TemplateFileCreator objects, each with: + * app, label, extension, mimetypes[], templates[] + * + * @return {Promise} + */ +export async function getTemplates() { + const response = await axios.get(generateOcsUrl('apps/files/api/v1/templates')) + return response.data.ocs.data +} + +/** + * Create a new file from a template via the NC Files API. + * + * @param {string} filePath Destination path for the new file + * @param {string} templatePath Source template path + * @param {string} templateType Template type e.g. 'user' + * @return {Promise} + */ +export async function createFromTemplate(filePath, templatePath, templateType) { + const response = await axios.post(generateOcsUrl('apps/files/api/v1/templates/create'), { + filePath, + templatePath, + templateType, + }) + return response.data.ocs.data +} diff --git a/src/view/Office.vue b/src/view/Office.vue index a0abaf0449..129af78c98 100644 --- a/src/view/Office.vue +++ b/src/view/Office.vue @@ -676,6 +676,7 @@ export default { height: 100dvh; top: -50px; position: absolute; + z-index: 10001; } [data-handler="richdocuments"] .modal-header { diff --git a/src/views/OfficeOverview.vue b/src/views/OfficeOverview.vue new file mode 100644 index 0000000000..4b8666b040 --- /dev/null +++ b/src/views/OfficeOverview.vue @@ -0,0 +1,214 @@ + + + + + + diff --git a/templates/overview.php b/templates/overview.php new file mode 100644 index 0000000000..0024bd549b --- /dev/null +++ b/templates/overview.php @@ -0,0 +1,8 @@ + +
diff --git a/tests/features/bootstrap/SettingsContext.php b/tests/features/bootstrap/SettingsContext.php index d193ff1908..c1a26dac36 100644 --- a/tests/features/bootstrap/SettingsContext.php +++ b/tests/features/bootstrap/SettingsContext.php @@ -19,6 +19,9 @@ class SettingsContext implements Context { /** @var ServerContext */ private $serverContext; + /** @var WopiContext */ + private $wopiContext; + /** @var GuzzleHttp\Client */ private $http; @@ -32,6 +35,7 @@ public function __construct() { #[BeforeScenario] public function gatherContexts(BeforeScenarioScope $scope) { $this->serverContext = $scope->getEnvironment()->getContext(ServerContext::class); + $this->wopiContext = $scope->getEnvironment()->getContext(WopiContext::class); $this->http = new GuzzleHttp\Client([ 'base_uri' => $this->serverContext->getBaseUrl() . 'index.php/apps/richdocuments/', @@ -130,6 +134,43 @@ public function adminRequestAdminSettings() { }); } + #[When('user :user uploads a user configuration file')] + public function userUploadsUserConfigFile(string $user) { + $this->serverContext->actingAsUser($user); + + $settingsAccessToken = $this->getSettingsAccessToken('user'); + $postOptions = [ + 'query' => [ + 'access_token' => $settingsAccessToken, + 'fileId' => '/settings/userconfig/wordbook/poc.dic', + ], + 'body' => 'fake dictionary', + ]; + + $options = array_merge($this->serverContext->getWebOptions(), $postOptions); + $this->http->post('wopi/settings/upload', $options); + } + + #[When('user :user requests their own user configuration file')] + public function userRequestsOwnUserConfigFile(string $user) { + $this->serverContext->actingAsUser($user); + + $token = $this->getSettingsAccessToken('user'); + $this->httpResponse = $this->http->get( + "settings/userconfig/$token/wordbook/poc.dic", + $this->serverContext->getWebOptions() + ); + } + + #[When('the guest uses the share token to request the user configuration file')] + public function guestRequestsUserConfigFileWithShareToken() { + $guestToken = $this->wopiContext->getWopiToken(); + + $this->httpResponse = $this->http->get( + "settings/userconfig/$guestToken/wordbook/poc.dic" + ); + } + #[Then('the admin settings are forbidden')] public function adminSettingsRequestForbidden() { Assert::assertEquals(403, $this->httpResponse->getStatusCode()); @@ -169,6 +210,16 @@ public function systemConfigDeletionAllowed() { Assert::assertEquals(200, $this->httpResponse->getStatusCode()); } + #[Then('the user configuration file is returned')] + public function userConfigFileRequestIsSuccessful() { + Assert::assertEquals(200, $this->httpResponse->getStatusCode()); + } + + #[Then('the user configuration file is forbidden')] + public function userConfigFileAccessIsForbidden() { + Assert::assertEquals(403, $this->httpResponse->getStatusCode()); + } + private function getSettingsAccessToken(string $type) { $options = $this->serverContext->getWebOptions(); diff --git a/tests/features/bootstrap/WopiContext.php b/tests/features/bootstrap/WopiContext.php index 8b5fd6e5f7..0e569d287e 100644 --- a/tests/features/bootstrap/WopiContext.php +++ b/tests/features/bootstrap/WopiContext.php @@ -315,4 +315,43 @@ public function collaboraRenamesTo($fileId, $newName) { $this->response = $e->getResponse(); } } + + /** + * @When /^Collabora fetches checkFileInfo for version "([^"]*)"$/ + */ + public function collaboraFetchesCheckFileInfoForVersion($version) { + $client = new Client(); + // Ensure we set the version as the third underscore-separated part + $arr = explode('_', $this->fileId); + if (count($arr) >= 3) { + $arr[2] = (string)$version; + } else { + $arr[] = (string)$version; + } + $fid = implode('_', $arr); + $options = []; + try { + $this->response = $client->get($this->getWopiEndpointBaseUrl() . 'index.php/apps/richdocuments/wopi/files/' . $fid . '?access_token=' . $this->wopiToken, $options); + $this->checkFileInfoResult = json_decode($this->response->getBody()->getContents(), true); + } catch (\GuzzleHttp\Exception\ClientException $e) { + $this->response = $e->getResponse(); + } + } + + /** + * @When /^I perform "(\d+)" guest checkFileInfo requests$/ + */ + public function performGuestCheckFileInfoRequests($count) { + $client = new Client(); + $last = null; + for ($i = 0; $i < intval($count); $i++) { + try { + $resp = $client->get($this->getWopiEndpointBaseUrl() . 'index.php/apps/richdocuments/wopi/files/' . $this->fileId . '?access_token=' . $this->wopiToken); + $last = $resp; + } catch (\GuzzleHttp\Exception\ClientException $e) { + $last = $e->getResponse(); + } + $this->response = $last; + } + } } diff --git a/tests/features/user-settings.feature b/tests/features/user-settings.feature new file mode 100644 index 0000000000..bafd6359a9 --- /dev/null +++ b/tests/features/user-settings.feature @@ -0,0 +1,21 @@ +Feature: User Settings + + Background: + Given user "user1" exists + + Scenario: A user can retrieve their own user configuration file + When user "user1" uploads a user configuration file + And user "user1" requests their own user configuration file + Then the user configuration file is returned + + Scenario: A guest cannot access a user's configuration file using a public share token + Given as user "user1" + And User "user1" uploads file "./../emptyTemplates/template.odt" to "/test.odt" + And as "user1" create a share with + | path | /test.odt | + | shareType | 3 | + | permissions | 1 | + When user "user1" uploads a user configuration file + And A guest opens the file "test.odt" in the last share link through direct editing + And the guest uses the share token to request the user configuration file + Then the user configuration file is forbidden diff --git a/tests/features/wopi.feature b/tests/features/wopi.feature index be7ebcb894..a514739340 100644 --- a/tests/features/wopi.feature +++ b/tests/features/wopi.feature @@ -375,4 +375,27 @@ Feature: WOPI And as "user1" rename "/SharedFolder/file.odt" to "renamed_file" And as "user1" the file "/SharedFolder/renamed_file.odt" exists And as "user1" the file "/SharedFolder/file.odt" does not exist - And as "user1" the file "/renamed_file.odt" does not exist \ No newline at end of file + And as "user1" the file "/renamed_file.odt" does not exist + + + Scenario: Public share cannot request a specific saved version + Given as user "user1" + And User "user1" uploads file "./../emptyTemplates/template.odt" to "/file.odt" + And as "user1" create a share with + | path | /file.odt | + | shareType | 3 | + Then Using web as guest + And a guest opens the share link + When Collabora fetches checkFileInfo for version "1" + Then the WOPI HTTP status code should be "403" + + Scenario: Guest repeated checkFileInfo requests are rate-limited + Given as user "user1" + And User "user1" uploads file "./../emptyTemplates/template.odt" to "/file.odt" + And as "user1" create a share with + | path | /file.odt | + | shareType | 3 | + Then Using web as guest + And a guest opens the share link + When I perform "11" guest checkFileInfo requests + Then the WOPI HTTP status code should be "429" \ No newline at end of file diff --git a/tests/lib/Controller/OverviewControllerTest.php b/tests/lib/Controller/OverviewControllerTest.php new file mode 100644 index 0000000000..8ef5d5a911 --- /dev/null +++ b/tests/lib/Controller/OverviewControllerTest.php @@ -0,0 +1,76 @@ +eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->initialState = $this->createMock(IInitialState::class); + $this->preview = $this->createMock(IPreview::class); + + $this->controller = new OverviewController( + 'richdocuments', + $this->createMock(IRequest::class), + $this->eventDispatcher, + $this->initialState, + $this->preview, + ); + } + + public function testIndexReturnsTemplateResponse(): void { + $response = $this->controller->index(); + + $this->assertInstanceOf(TemplateResponse::class, $response); + $this->assertSame('richdocuments', $response->getApp()); + $this->assertSame('overview', $response->getTemplateName()); + $this->assertSame('#app-content-vue', $response->getParams()['id-app-content']); + $this->assertSame('#app-navigation-vue', $response->getParams()['id-app-navigation']); + } + + public function testIndexSetsPreviewEnabledTrue(): void { + $this->preview->expects($this->once()) + ->method('isMimeSupported') + ->with('application/vnd.oasis.opendocument.text') + ->willReturn(true); + + $this->initialState->expects($this->once()) + ->method('provideInitialState') + ->with('previewEnabled', true); + + $this->controller->index(); + } + + public function testIndexSetsPreviewEnabledFalse(): void { + $this->preview->expects($this->once()) + ->method('isMimeSupported') + ->with('application/vnd.oasis.opendocument.text') + ->willReturn(false); + + $this->initialState->expects($this->once()) + ->method('provideInitialState') + ->with('previewEnabled', false); + + $this->controller->index(); + } +} diff --git a/tests/lib/Service/ProofKeyServiceTest.php b/tests/lib/Service/ProofKeyServiceTest.php index b1f6b35c3e..00f7cc00f6 100644 --- a/tests/lib/Service/ProofKeyServiceTest.php +++ b/tests/lib/Service/ProofKeyServiceTest.php @@ -56,12 +56,14 @@ public function setUp(): void { $this->proofKeyService = new ProofKeyService($this->discoveryService); } - public function testWindowsToUnixTimestamp(): void { - // Timestamps representing 15 February, 2024 00:00:00 - $windowsTimestamp = '133524468000000000'; - $expectedUnixTimestamp = '1707973200'; + public function testTicksToUnixTimestamp(): void { + // .NET ticks representing the Unix epoch + $ticksUnixEpoch = 621355968000000000; - $unixTimestamp = $this->proofKeyService->windowsToUnixTimestamp($windowsTimestamp); + // The conversion should result in a Unix timestamp of 0 + $expectedUnixTimestamp = 0; + + $unixTimestamp = $this->proofKeyService->ticksToUnixTimestamp($ticksUnixEpoch); $this->assertEquals($expectedUnixTimestamp, $unixTimestamp); } diff --git a/tests/lib/Service/WopiRateLimitServiceTest.php b/tests/lib/Service/WopiRateLimitServiceTest.php new file mode 100644 index 0000000000..05e4545436 --- /dev/null +++ b/tests/lib/Service/WopiRateLimitServiceTest.php @@ -0,0 +1,64 @@ +limiter = $this->createMock(ILimiter::class); + $this->request = $this->createMock(IRequest::class); + $this->service = new WopiRateLimitService($this->limiter, $this->request); + } + + private function createWopiMock(int $id = 42): Wopi&MockObject { + $wopi = $this->getMockBuilder(Wopi::class) + ->addMethods(['getId']) + ->getMock(); + $wopi->method('getId')->willReturn($id); + return $wopi; + } + + public function testRegisterRequestCallsLimiterWithCorrectParameters(): void { + $wopi = $this->createWopiMock(7); + $this->request->method('getRemoteAddress')->willReturn('127.0.0.1'); + + $this->limiter->expects($this->once()) + ->method('registerAnonRequest') + ->with( + 'richdocuments::wopi::checkFileInfo::7', + 10, + 120, + '127.0.0.1' + ); + + $this->service->registerRequest($wopi, 'checkFileInfo'); + } + + public function testRegisterRequestPropagatesRateLimitExceeded(): void { + $wopi = $this->createWopiMock(); + $this->request->method('getRemoteAddress')->willReturn('127.0.0.1'); + + $exception = $this->createMock(IRateLimitExceededException::class); + $this->limiter->method('registerAnonRequest')->willThrowException($exception); + + $this->expectException(IRateLimitExceededException::class); + $this->service->registerRequest($wopi, 'checkFileInfo'); + } +} diff --git a/webpack.js b/webpack.js index c2d77b49ae..3ce6d64113 100644 --- a/webpack.js +++ b/webpack.js @@ -13,6 +13,7 @@ webpackConfig.entry = { 'init-viewer': path.join(__dirname, 'src', 'init-viewer.js'), fileActions: path.join(__dirname, 'src', 'file-actions.js'), document: path.join(__dirname, 'src', 'document.js'), + overview: path.join(__dirname, 'src', 'overview.js'), admin: path.join(__dirname, 'src', 'admin.js'), personal: path.join(__dirname, 'src', 'personal.js'), reference: path.join(__dirname, 'src', 'reference.js'),