Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
1ec1563
added folderUuid and parentUuid properties
larryrider Oct 28, 2024
5b6bc45
updated and fixed rename operation
larryrider Oct 29, 2024
0ac245e
added toItem type conversion utility
larryrider Oct 29, 2024
882643b
forced database reset on every init
larryrider Oct 29, 2024
8e85bad
clean database on every start
larryrider Oct 29, 2024
6f4f0bf
improved webdav resource management via webdav utils
larryrider Oct 29, 2024
f2e7120
added get item by path functionality
larryrider Oct 30, 2024
ef6bde0
added move handler for both renaming and moving items
larryrider Oct 30, 2024
6b2f8ae
Merge branch 'main' into feat/pb-1780-move-and-rename-items
larryrider Oct 30, 2024
75a2014
fixed and improved DELETE handler and tests
larryrider Oct 30, 2024
cd50860
fixed and improved GET handler and tests
larryrider Oct 31, 2024
01da425
fixed tests and improved try-catch testing
larryrider Oct 31, 2024
a7a09d7
improved resource fixture
larryrider Oct 31, 2024
7a0c8cc
fixed and improved MKCOL handler and tests
larryrider Oct 31, 2024
80de71a
fixed and improved HEAD handler and tests
larryrider Oct 31, 2024
5d0fc5c
fixed and improved OPTIONS handler and tests
larryrider Oct 31, 2024
9aa55d8
fixed and improved PROPFIND handler and tests
larryrider Nov 4, 2024
c537244
fixed and improved PUT handler and tests
larryrider Nov 4, 2024
5905aca
added config command to allow changing webdav protocol and port
larryrider Nov 5, 2024
38f93da
renew selfsigned ssl certs if they are expired
larryrider Nov 5, 2024
5d21d41
updated readme
larryrider Nov 5, 2024
900b949
improved add-cert linux script
larryrider Nov 5, 2024
39b28c2
added some tests
larryrider Nov 5, 2024
1f5ae82
bumped sdk version
larryrider Nov 5, 2024
c640b25
fixed sonarcloud issues
larryrider Nov 5, 2024
5ac4eb4
fixed tests
larryrider Nov 5, 2024
8bf89e1
added tests
larryrider Nov 6, 2024
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
1 change: 0 additions & 1 deletion .env.template
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,5 @@ APP_CRYPTO_SECRET=6KYQBP847D4ATSFA
APP_CRYPTO_SECRET2=8Q8VMUE3BJZV87GT
APP_MAGIC_IV=d139cb9a2cd17092e79e1861cf9d7023
APP_MAGIC_SALT=38dce0391b49efba88dbc8c39ebf868f0267eb110bb0012ab27dc52a528d61b1d1ed9d76f400ff58e3240028442b1eab9bb84e111d9dadd997982dbde9dbd25e
WEBDAV_SERVER_PORT=3005
RUDDERSTACK_WRITE_KEY=
RUDDERSTACK_DATAPLANE_URL=
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ USAGE
* [`internxt trash restore`](#internxt-trash-restore-1)
* [`internxt upload`](#internxt-upload)
* [`internxt webdav ACTION`](#internxt-webdav-action)
* [`internxt webdav-config ACTION`](#internxt-webdav-config-action)
* [`internxt whoami`](#internxt-whoami)

## `internxt add-cert`
Expand Down Expand Up @@ -544,6 +545,34 @@ EXAMPLES

_See code: [src/commands/webdav.ts](https://github.com/internxt/cli/blob/v1.3.0/src/commands/webdav.ts)_

## `internxt webdav-config ACTION`

Edit the configuration of the Internxt CLI WebDav server as the port or the protocol.

```
USAGE
$ internxt webdav-config ACTION [-n] [-p <value>]

FLAGS
-p, --port=<value> The new port that the WebDAV server is going to be have.

HELPER FLAGS
-n, --non-interactive Blocks the cli from being interactive. If passed, the cli will not request data through the
console and will throw errors directly

DESCRIPTION
Edit the configuration of the Internxt CLI WebDav server as the port or the protocol.

EXAMPLES
$ internxt webdav-config set-http

$ internxt webdav-config set-https

$ internxt webdav-config change-port
```

_See code: [src/commands/webdav-config.ts](https://github.com/internxt/cli/blob/v1.3.0/src/commands/webdav-config.ts)_

## `internxt whoami`

Display the current user logged into the Internxt CLI.
Expand Down
7 changes: 3 additions & 4 deletions WEBDAV.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,13 @@ Find below the methods that are supported in the latest version of the Internxt
| OPTIONS | ✅ |
| GET | ✅ |
| HEAD | ✅ |
| POST | ❌ |
| PUT | ✅ |
| DELETE | ✅ |
| PROPFIND | ✅ |
| PROPPATCH | ❌ |
| MKCOL | ✅ |
| COPY | ❌ |
| MOVE | |
| MOVE | |

## Requisites

Expand All @@ -61,6 +60,6 @@ Find below the methods that are supported in the latest version of the Internxt

## Known issues

- We use selfsigned certificates, so all the requests to the WebDav local server are encrypted, since the certificates are selfsigned, many WebDav clients will complain about the certificates trust. You can safely ignore this warning.
- We use self-signed certificates when using HTTPS. This ensures that all requests to the local WebDAV server are encrypted. However, since the certificates are self-signed, many WebDAV clients may show warnings about certificate trust. You can safely ignore these warnings.

- You may encounter issues with the DNS resolution of webdav.local.internxt.com. In such cases, you can safely replace this address with 127.0.0.1, or the corresponding IP where you have deployed the webdav server if you are connecting from another location.
- You may encounter issues with DNS resolution for webdav.local.internxt.com. In such cases, you can safely replace this address with 127.0.0.1 or the IP address where the WebDAV server is deployed if connecting from a different location.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"dependencies": {
"@internxt/inxt-js": "^2.0.11",
"@internxt/lib": "^1.2.1",
"@internxt/sdk": "^1.5.17",
"@internxt/sdk": "^1.5.25",
"@oclif/core": "^3",
"@rudderstack/rudder-sdk-node": "^2.0.7",
"axios": "^1.6.7",
Expand Down
24 changes: 19 additions & 5 deletions scripts/add-cert.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
#!/bin/bash

CERT_PATH=$1
CERT_PATH="$1"

if [[ -z "$CERT_PATH" ]]; then
echo "Usage: $0 path_to_certificate"
exit 1
fi

if [[ "$OSTYPE" == "darwin"* ]]; then
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain $CERT_PATH
else
sudo cp $CERT_PATH /usr/local/share/ca-certificates/
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain "$CERT_PATH"
elif [[ -d "/usr/local/share/ca-certificates/" ]]; then # For Debian-based distributions
sudo cp "$CERT_PATH" /usr/local/share/ca-certificates/
sudo update-ca-certificates
fi
elif [[ -d "/etc/pki/ca-trust/source/anchors/" ]]; then # For Fedora-based distribution
sudo cp "$CERT_PATH" /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust -i
elif [[ -d "/etc/ca-certificates/trust-source/anchors/" ]]; then # For Arch Linux and derivatives
sudo cp "$CERT_PATH" /etc/ca-certificates/trust-source/anchors/
sudo trust extract-compat
else
echo "Local certificates folder not found"
exit 1
fi
2 changes: 1 addition & 1 deletion src/commands/rename.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export default class Rename extends Command {
if (isFolder) {
await DriveFolderService.instance.renameFolder({ folderUuid: item.uuid, name: newName });
} else {
await DriveFileService.instance.renameFile({ fileUuid: item.uuid, name: newName });
await DriveFileService.instance.renameFile(item.uuid, { plainName: newName });
}
CLIUtils.success(`${isFolder ? 'Folder' : 'File'} renamed successfully with: ${newName}`);
}
Expand Down
106 changes: 106 additions & 0 deletions src/commands/webdav-config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { Args, Command, Flags } from '@oclif/core';
import { ConfigService } from '../services/config.service';
import { CLIUtils } from '../utils/cli.utils';
import { ErrorUtils } from '../utils/errors.utils';
import { NotValidPortError } from '../types/command.types';
import { ValidationService } from '../services/validation.service';

export default class WebDAVConfig extends Command {
static readonly description = 'Edit the configuration of the Internxt CLI WebDav server as the port or the protocol.';
static readonly args = {
action: Args.string({
required: true,
options: ['set-http', 'set-https', 'change-port'],
}),
};
static readonly examples = [
'<%= config.bin %> <%= command.id %> set-http',
'<%= config.bin %> <%= command.id %> set-https',
'<%= config.bin %> <%= command.id %> change-port',
];
static readonly flags = {
...CLIUtils.CommonFlags,
port: Flags.string({
char: 'p',
description: 'The new port that the WebDAV server is going to be have.',
required: false,
}),
};

public async run(): Promise<void> {
const { args, flags } = await this.parse(WebDAVConfig);
const nonInteractive = flags['non-interactive'];
const webdavConfig = await ConfigService.instance.readWebdavConfig();

if (args.action !== 'change-port' && flags['port']) {
CLIUtils.warning('The port flag will be ignored; it can only be used with the "change-port" action.');
}

switch (args.action) {
case 'set-http': {
await ConfigService.instance.saveWebdavConfig({
...webdavConfig,
protocol: 'http',
});
CLIUtils.success('On the next start, the WebDAV server will use HTTP.');
break;
}

case 'set-https': {
await ConfigService.instance.saveWebdavConfig({
...webdavConfig,
protocol: 'https',
});
CLIUtils.success('On the next start, the WebDAV server will use HTTPS.');
break;
}

case 'change-port': {
const newPort = await this.getWebDAVPort(flags['port'], nonInteractive);
await ConfigService.instance.saveWebdavConfig({
...webdavConfig,
port: newPort,
});
CLIUtils.success('For the next start, the Webdav server will be served at the new port: ' + newPort);
break;
}
}
}

async catch(error: Error) {
ErrorUtils.report(error, { command: this.id });
CLIUtils.error(error.message);
this.exit(1);
}

private static readonly MAX_ATTEMPTS = 3;

public getWebDAVPort = async (webdavPortFlag: string | undefined, nonInteractive: boolean): Promise<string> => {
let port = CLIUtils.getValueFromFlag(
{
value: webdavPortFlag,
name: WebDAVConfig.flags['port'].name,
error: new NotValidPortError(),
canBeEmpty: true,
},
nonInteractive,
(port: string) => ValidationService.instance.validateTCPIntegerPort(port),
);
if (!port) {
port = (await this.getNewWebDAVPortInteractively()).trim();
}
return port;
};

public getNewWebDAVPortInteractively = (): Promise<string> => {
return CLIUtils.promptWithAttempts(
{
message: 'What is the new WebDAV server port?',
options: { required: false },
error: new NotValidPortError(),
},
WebDAVConfig.MAX_ATTEMPTS,
(port: string) => ValidationService.instance.validateTCPIntegerPort(port),
);
};
}
9 changes: 8 additions & 1 deletion src/commands/webdav.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ConfigService } from '../services/config.service';
import { AnalyticsService } from '../services/analytics.service';
import { AuthService } from '../services/auth.service';
import { DriveDatabaseManager } from '../services/database/drive-database-manager.service';

export default class Webdav extends Command {
static readonly description = 'Enable, disable, restart or get the status of the Internxt CLI WebDav server';

Expand All @@ -23,18 +24,24 @@ export default class Webdav extends Command {
options: ['enable', 'disable', 'restart', 'status'],
}),
};

public async enableWebDav() {
CLIUtils.doing('Starting Internxt WebDav server...');
await DriveDatabaseManager.clean();
await PM2Utils.connect();
await PM2Utils.killWebDavServer();
await PM2Utils.startWebDavServer();
CLIUtils.done();
const { status } = await PM2Utils.webdavServerStatus();
const webdavConfigs = await ConfigService.instance.readWebdavConfig();

if (status === 'online') {
ux.log(`\nWebDav server status: ${ux.colorize('green', 'online')}\n`);
CLIUtils.success(
`Internxt WebDav server started successfully on https://${ConfigService.WEBDAV_LOCAL_URL}:${process.env.WEBDAV_SERVER_PORT}`,
`Internxt WebDav server started successfully at ${webdavConfigs.protocol}://${ConfigService.WEBDAV_LOCAL_URL}:${webdavConfigs.port}`,
);
ux.log(
`\n[If the above URL is not working, the WebDAV server can be accessed directly via your localhost IP at: ${webdavConfigs.protocol}://127.0.0.1:${webdavConfigs.port} ]\n`,
);
const authDetails = await AuthService.instance.getAuthDetails();
await AnalyticsService.instance.track('WebDAVEnabled', { app: 'internxt-cli', userId: authDetails.user.uuid });
Expand Down
25 changes: 25 additions & 0 deletions src/database/migrations/20241018114828-add-parent-column.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { QueryInterface, DataTypes } from 'sequelize';

/** @type {import('sequelize-cli').Migration} */
module.exports = {
async up(queryInterface: QueryInterface, Sequelize: typeof DataTypes) {
await queryInterface.addColumn('folders', 'parent_uuid', {
type: Sequelize.UUIDV4,
references: {
model: 'folders',
key: 'uuid',
},
});
await queryInterface.addColumn('files', 'folder_uuid', {
type: Sequelize.UUIDV4,
references: {
model: 'files',
key: 'uuid',
},
});
},
async down(queryInterface: QueryInterface) {
await queryInterface.removeColumn('folders', 'parent_uuid');
await queryInterface.removeColumn('files', 'folder_uuid');
},
};
3 changes: 2 additions & 1 deletion src/hooks/prerun/auth_check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { SdkManager } from '../../services/sdk-manager.service';
import { AuthService } from '../../services/auth.service';
import { MissingCredentialsError } from '../../types/command.types';
import Webdav from '../../commands/webdav';
import WebDAVConfig from '../../commands/webdav-config';

const CommandsToSkip = [Whoami, Login, Logout, Logs, Webdav];
const CommandsToSkip = [Whoami, Login, Logout, Logs, Webdav, WebDAVConfig];
const hook: Hook<'prerun'> = async function (opts) {
if (!CommandsToSkip.map((command) => command.name).includes(opts.Command.name)) {
CLIUtils.doing('Checking credentials');
Expand Down
8 changes: 4 additions & 4 deletions src/services/analytics.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Rudderstack, { apiObject } from '@rudderstack/rudder-sdk-node';
import { apiObject } from '@rudderstack/rudder-sdk-node';
import { ConfigService } from './config.service';
//import packageJSON from '../../package.json';
//import os from 'os';
Expand All @@ -12,9 +12,9 @@ export const AnalyticsEvents = {
export class AnalyticsService {
public static readonly instance: AnalyticsService = new AnalyticsService(ConfigService.instance);

constructor(private config: ConfigService) {}
constructor(private readonly config: ConfigService) {}

private getRudderstack() {
/*private getRudderstack() {
return new Rudderstack(this.config.get('RUDDERSTACK_WRITE_KEY'), {
dataPlaneUrl: this.config.get('RUDDERSTACK_DATAPLANE_URL'),
});
Expand Down Expand Up @@ -44,7 +44,7 @@ export class AnalyticsService {
default:
return 'Unknown';
}
}
}*/

track(
eventKey: keyof typeof AnalyticsEvents,
Expand Down
27 changes: 26 additions & 1 deletion src/services/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import path from 'path';
import os from 'os';
import fs from 'fs/promises';
import { ConfigKeys } from '../types/config.types';
import { CLICredentials } from '../types/command.types';
import { CLICredentials, WebdavConfig } from '../types/command.types';
import { CryptoService } from './crypto.service';

export class ConfigService {
Expand All @@ -12,7 +12,10 @@ export class ConfigService {
static readonly CREDENTIALS_FILE = path.join(this.INTERNXT_CLI_DATA_DIR, '.inxtcli');
static readonly DRIVE_SQLITE_FILE = path.join(this.INTERNXT_CLI_DATA_DIR, 'internxt-cli-drive.sqlite');
static readonly WEBDAV_SSL_CERTS_DIR = path.join(this.INTERNXT_CLI_DATA_DIR, 'certs');
static readonly WEBDAV_CONFIGS_FILE = path.join(this.INTERNXT_CLI_DATA_DIR, 'config.webdav.inxt');
static readonly WEBDAV_LOCAL_URL = 'webdav.local.internxt.com';
static readonly WEBDAV_DEFAULT_PORT = '3005';
static readonly WEBDAV_DEFAULT_PROTOCOL = 'https';
public static readonly instance: ConfigService = new ConfigService();

/**
Expand Down Expand Up @@ -71,6 +74,28 @@ export class ConfigService {
}
};

public saveWebdavConfig = async (webdavConfig: WebdavConfig): Promise<void> => {
await this.ensureInternxtCliDataDirExists();
const configs = JSON.stringify(webdavConfig);
await fs.writeFile(ConfigService.WEBDAV_CONFIGS_FILE, configs, 'utf8');
};

public readWebdavConfig = async (): Promise<WebdavConfig> => {
try {
const configsData = await fs.readFile(ConfigService.WEBDAV_CONFIGS_FILE, 'utf8');
const configs = JSON.parse(configsData);
return {
port: configs?.port ?? ConfigService.WEBDAV_DEFAULT_PORT,
protocol: configs?.protocol ?? ConfigService.WEBDAV_DEFAULT_PROTOCOL,
};
} catch {
return {
port: ConfigService.WEBDAV_DEFAULT_PORT,
protocol: ConfigService.WEBDAV_DEFAULT_PROTOCOL,
};
}
};

ensureInternxtCliDataDirExists = async () => {
try {
await fs.access(ConfigService.INTERNXT_CLI_DATA_DIR);
Expand Down
Loading