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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,36 @@ However, using portable `zip` distribution, you can have several Nextcloud Talk
└── ...
```

## ⌨️ CLI usage

### Application flags

Adjust how the application runs when launching.

| Flag | Description |
|----------------|-------------------------------------------------------------------------------|
| `--background` | Start minimized to the system tray without a window (used for run at startup) |

### CLI commands

Run a command in the app and quit without launching the entire app.

#### `config`

Set application configuration.

| Option | Description |
|----------------------------|--------------------------------------------|
| `--accounts=[user@]server` | Comma-separated list of prefilled accounts |

Examples:

```sh
./Nextcloud\ Talk config --accounts=cloud.company.tld
./Nextcloud\ Talk config --accounts='Name Surname@cloud.company.tld'
./Nextcloud\ Talk config --accounts=name@email.tld@company.tld/nextcloud
```

## 🛠️ Development Setup

1. Install dependencies
Expand Down
15 changes: 15 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
"core-js": "^3.47.0",
"electron-squirrel-startup": "^1.0.1",
"howler": "^2.2.4",
"mri": "^1.2.0",
"pinia": "^3.0.4",
"semver": "^7.7.3",
"unzip-crx-3": "^0.2.0",
Expand Down
69 changes: 69 additions & 0 deletions src/app/cli.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*!
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

import type { Argv } from 'mri'

import { app } from 'electron'
import { setAppConfig } from './AppConfig.ts'

/**
* Handle CLI usage
*
* @param argv - Parsed by mri CLI arguments
*/
export async function cli(argv: Argv) {
// TODO: Add --help command

if (!argv._.length) {
return
}

if (argv._[0] === 'config' && argv._.length === 1) {
await handleConfigCommand(argv)
} else {
console.log('Unknown command:', argv._.join(' '))
app.exit(1)
}

app.exit(0)
}

/**
* Handle "config" CLI command
*
* @param argv - Parsed by mri CLI arguments
*/
async function handleConfigCommand(argv: Argv) {
if (!argv.accounts) {
console.log('No config to set')
app.exit(1)
}

// --accounts=user@email.tld@server.tld/nextcloud,nextcloud.local
const accounts = argv.accounts.split(',')

// Validate
for (const account of accounts) {
const atIndex = account.lastIndexOf('@')
const [server, user] = atIndex === -1
? [account, '']
: [account.slice(atIndex + 1), account.slice(0, atIndex)]
try {
new URL(`https://${server}`)
} catch {
console.error(`Invalid server: ${server}`)
app.exit(1)
}
if (user && (!/^[a-zA-Z0-9 _.@\-']{1,64}$/.test(user) || user !== user.trim())) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: does it cover all Nextcloud/LDAP/SSO/SAML cases? I remember some issues or report with the latter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesn't check everything, so it is even a bit wider than actual requirements. A minimal check to have allowed characters and trim.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most common unexpected issue - spaces are allowed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good enough for now, we can fix it later if someone had an issue

console.error(`Invalid user: ${user}`)
app.exit(1)
}
}

// Set
await setAppConfig('accounts', accounts)

console.log('Accounts configuration updated')
}
15 changes: 7 additions & 8 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
*/

const { app, ipcMain, desktopCapturer, systemPreferences, shell, session } = require('electron')
const { default: mri } = require('mri')
const { spawn } = require('node:child_process')
const path = require('node:path')
const { setupMenu } = require('./app/app.menu.js')
const { loadAppConfig, getAppConfig, setAppConfig } = require('./app/AppConfig.ts')
const { appData } = require('./app/AppData.js')
const { registerAppProtocolHandler } = require('./app/appProtocol.ts')
const { verifyCertificate, promptCertificateTrust } = require('./app/certificate.service.ts')
const { cli } = require('./app/cli.ts')
const { openChromeWebRtcInternals } = require('./app/dev.utils.ts')
const { triggerDownloadUrl } = require('./app/downloads.ts')
const { setupReleaseNotificationScheduler, checkForUpdate } = require('./app/githubRelease.service.ts')
Expand All @@ -30,13 +32,7 @@ const { createTalkWindow } = require('./talk/talk.window.js')
const { createUpgradeWindow } = require('./upgrade/upgrade.window.ts')
const { createWelcomeWindow } = require('./welcome/welcome.window.js')

/**
* Parse command line arguments
*/
const ARGUMENTS = {
// Open Talk window in the background, minimized to the system tray
openInBackground: process.argv.includes('--background'),
}
const argv = mri(process.argv.slice(app.isPackaged ? 1 : 2))

// Electron 36 with Chromium 136 is not compatible with GNOME due to GTK3 with GTK4 mixing
// Workaround: force GTK3
Expand Down Expand Up @@ -74,6 +70,7 @@ if (require('electron-squirrel-startup')) {
* Only one instance is allowed at the same time
*/
if (!app.requestSingleInstanceLock()) {
console.log('Another instance of the app is already running')
app.quit()
}

Expand Down Expand Up @@ -137,6 +134,8 @@ app.whenReady().then(async () => {
await loadAppConfig()
await runMigrations()

await cli(argv)

applyTheme()
initLaunchAtStartupListener()
registerAppProtocolHandler()
Expand All @@ -149,7 +148,7 @@ app.whenReady().then(async () => {
}

// Open in the background if it is explicitly set, or the app was open at login on macOS
const openInBackground = ARGUMENTS.openInBackground || app.getLoginItemSettings().wasOpenedAtLogin
const openInBackground = argv.background || app.getLoginItemSettings().wasOpenedAtLogin

try {
await installVueDevtools()
Expand Down
Loading