forked from Cutlery/immich
		
	fix(cli): auth file should be chmod 600 (#6925)
* wip new tests * test for auth file mode * check perms internally * chore: lint
This commit is contained in:
		
							parent
							
								
									6ed33da2a4
								
							
						
					
					
						commit
						ce6dc3b7af
					
				
							
								
								
									
										32
									
								
								cli/package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										32
									
								
								cli/package-lock.json
									
									
									
										generated
									
									
									
								
							@ -3810,6 +3810,15 @@
 | 
			
		||||
        "get-func-name": "^2.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/lru-cache": {
 | 
			
		||||
      "version": "10.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "14 || >=16.14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/magic-string": {
 | 
			
		||||
      "version": "0.30.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
 | 
			
		||||
@ -4182,15 +4191,6 @@
 | 
			
		||||
        "url": "https://github.com/sponsors/isaacs"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/path-scurry/node_modules/lru-cache": {
 | 
			
		||||
      "version": "10.0.1",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz",
 | 
			
		||||
      "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==",
 | 
			
		||||
      "dev": true,
 | 
			
		||||
      "engines": {
 | 
			
		||||
        "node": "14 || >=16.14"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/path-type": {
 | 
			
		||||
      "version": "4.0.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
 | 
			
		||||
@ -8566,6 +8566,12 @@
 | 
			
		||||
        "get-func-name": "^2.0.1"
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "lru-cache": {
 | 
			
		||||
      "version": "10.2.0",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
 | 
			
		||||
      "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
 | 
			
		||||
      "dev": true
 | 
			
		||||
    },
 | 
			
		||||
    "magic-string": {
 | 
			
		||||
      "version": "0.30.5",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz",
 | 
			
		||||
@ -8834,14 +8840,6 @@
 | 
			
		||||
      "requires": {
 | 
			
		||||
        "lru-cache": "^9.1.1 || ^10.0.0",
 | 
			
		||||
        "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
 | 
			
		||||
      },
 | 
			
		||||
      "dependencies": {
 | 
			
		||||
        "lru-cache": {
 | 
			
		||||
          "version": "10.0.1",
 | 
			
		||||
          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz",
 | 
			
		||||
          "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==",
 | 
			
		||||
          "dev": true
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "path-type": {
 | 
			
		||||
 | 
			
		||||
@ -8,11 +8,11 @@ export abstract class BaseCommand {
 | 
			
		||||
  protected user!: UserResponseDto;
 | 
			
		||||
  protected serverVersion!: ServerVersionResponseDto;
 | 
			
		||||
 | 
			
		||||
  constructor(options: { config?: string }) {
 | 
			
		||||
    if (!options.config) {
 | 
			
		||||
  constructor(options: { configDirectory?: string }) {
 | 
			
		||||
    if (!options.configDirectory) {
 | 
			
		||||
      throw new Error('Config directory is required');
 | 
			
		||||
    }
 | 
			
		||||
    this.sessionService = new SessionService(options.config);
 | 
			
		||||
    this.sessionService = new SessionService(options.configDirectory);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async connect(): Promise<void> {
 | 
			
		||||
 | 
			
		||||
@ -82,7 +82,7 @@ export class SessionService {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await writeFile(this.authPath, yaml.stringify({ instanceUrl, apiKey }));
 | 
			
		||||
    await writeFile(this.authPath, yaml.stringify({ instanceUrl, apiKey }), { mode: 0o600 });
 | 
			
		||||
 | 
			
		||||
    console.log('Wrote auth info to ' + this.authPath);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ export const TEST_AUTH_FILE = path.join(TEST_CONFIG_DIR, 'auth.yml');
 | 
			
		||||
export const TEST_IMMICH_INSTANCE_URL = 'https://test/api';
 | 
			
		||||
export const TEST_IMMICH_API_KEY = 'pNussssKSYo5WasdgalvKJ1n9kdvaasdfbluPg';
 | 
			
		||||
 | 
			
		||||
export const CLI_BASE_OPTIONS = { config: TEST_CONFIG_DIR };
 | 
			
		||||
export const CLI_BASE_OPTIONS = { configDirectory: TEST_CONFIG_DIR };
 | 
			
		||||
 | 
			
		||||
export const setup = async () => {
 | 
			
		||||
  const api = new ImmichApi(process.env.IMMICH_INSTANCE_URL as string, '');
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,8 @@
 | 
			
		||||
import { restoreTempFolder, testApp } from '@test-utils';
 | 
			
		||||
import { CLI_BASE_OPTIONS, setup, spyOnConsole } from 'test/cli-test-utils';
 | 
			
		||||
import { CLI_BASE_OPTIONS, TEST_AUTH_FILE, deleteAuthFile, setup, spyOnConsole } from 'test/cli-test-utils';
 | 
			
		||||
import { readFile, stat } from 'node:fs/promises';
 | 
			
		||||
import { LoginCommand } from '../../src/commands/login';
 | 
			
		||||
import yaml from 'yaml';
 | 
			
		||||
 | 
			
		||||
describe(`login-key (e2e)`, () => {
 | 
			
		||||
  let apiKey: string;
 | 
			
		||||
@ -20,6 +22,7 @@ describe(`login-key (e2e)`, () => {
 | 
			
		||||
  afterAll(async () => {
 | 
			
		||||
    await testApp.teardown();
 | 
			
		||||
    await restoreTempFolder();
 | 
			
		||||
    deleteAuthFile();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  beforeEach(async () => {
 | 
			
		||||
@ -28,6 +31,8 @@ describe(`login-key (e2e)`, () => {
 | 
			
		||||
 | 
			
		||||
    const api = await setup();
 | 
			
		||||
    apiKey = api.apiKey;
 | 
			
		||||
 | 
			
		||||
    deleteAuthFile();
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should error when providing an invalid API key', async () => {
 | 
			
		||||
@ -39,4 +44,23 @@ describe(`login-key (e2e)`, () => {
 | 
			
		||||
  it('should log in when providing the correct API key', async () => {
 | 
			
		||||
    await new LoginCommand(CLI_BASE_OPTIONS).run(instanceUrl, apiKey);
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should create an auth file when logging in', async () => {
 | 
			
		||||
    await new LoginCommand(CLI_BASE_OPTIONS).run(instanceUrl, apiKey);
 | 
			
		||||
 | 
			
		||||
    const data: string = await readFile(TEST_AUTH_FILE, 'utf8');
 | 
			
		||||
    const parsedConfig = yaml.parse(data);
 | 
			
		||||
 | 
			
		||||
    expect(parsedConfig).toEqual(expect.objectContaining({ instanceUrl, apiKey }));
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  it('should create an auth file with chmod 600', async () => {
 | 
			
		||||
    await new LoginCommand(CLI_BASE_OPTIONS).run(instanceUrl, apiKey);
 | 
			
		||||
 | 
			
		||||
    const stats = await stat(TEST_AUTH_FILE);
 | 
			
		||||
 | 
			
		||||
    const mode = (stats.mode & 0o777).toString(8);
 | 
			
		||||
 | 
			
		||||
    expect(mode).toEqual('600');
 | 
			
		||||
  });
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user