|
|
|
|
@@ -1,12 +1,12 @@
|
|
|
|
|
import { LoginResponseDto, createApiKey } from '@immich/sdk';
|
|
|
|
|
import { LoginResponseDto, Permission, createApiKey } from '@immich/sdk';
|
|
|
|
|
import { createUserDto, uuidDto } from 'src/fixtures';
|
|
|
|
|
import { errorDto } from 'src/responses';
|
|
|
|
|
import { app, asBearerAuth, utils } from 'src/utils';
|
|
|
|
|
import request from 'supertest';
|
|
|
|
|
import { beforeAll, beforeEach, describe, expect, it } from 'vitest';
|
|
|
|
|
|
|
|
|
|
const create = (accessToken: string) =>
|
|
|
|
|
createApiKey({ apiKeyCreateDto: { name: 'api key' } }, { headers: asBearerAuth(accessToken) });
|
|
|
|
|
const create = (accessToken: string, permissions: Permission[]) =>
|
|
|
|
|
createApiKey({ apiKeyCreateDto: { name: 'api key', permissions } }, { headers: asBearerAuth(accessToken) });
|
|
|
|
|
|
|
|
|
|
describe('/api-keys', () => {
|
|
|
|
|
let admin: LoginResponseDto;
|
|
|
|
|
@@ -30,15 +30,65 @@ describe('/api-keys', () => {
|
|
|
|
|
expect(body).toEqual(errorDto.unauthorized);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not work without permission', async () => {
|
|
|
|
|
const { secret } = await create(user.accessToken, [Permission.ApiKeyRead]);
|
|
|
|
|
const { status, body } = await request(app).post('/api-keys').set('x-api-key', secret).send({ name: 'API Key' });
|
|
|
|
|
expect(status).toBe(403);
|
|
|
|
|
expect(body).toEqual(errorDto.missingPermission('apiKey.create'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should work with apiKey.create', async () => {
|
|
|
|
|
const { secret } = await create(user.accessToken, [Permission.ApiKeyCreate, Permission.ApiKeyRead]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.post('/api-keys')
|
|
|
|
|
.set('x-api-key', secret)
|
|
|
|
|
.send({
|
|
|
|
|
name: 'API Key',
|
|
|
|
|
permissions: [Permission.ApiKeyRead],
|
|
|
|
|
});
|
|
|
|
|
expect(body).toEqual({
|
|
|
|
|
secret: expect.any(String),
|
|
|
|
|
apiKey: {
|
|
|
|
|
id: expect.any(String),
|
|
|
|
|
name: 'API Key',
|
|
|
|
|
permissions: [Permission.ApiKeyRead],
|
|
|
|
|
createdAt: expect.any(String),
|
|
|
|
|
updatedAt: expect.any(String),
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
expect(status).toBe(201);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not create an api key with all permissions', async () => {
|
|
|
|
|
const { secret } = await create(user.accessToken, [Permission.ApiKeyCreate]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.post('/api-keys')
|
|
|
|
|
.set('x-api-key', secret)
|
|
|
|
|
.send({ name: 'API Key', permissions: [Permission.All] });
|
|
|
|
|
expect(status).toBe(400);
|
|
|
|
|
expect(body).toEqual(errorDto.badRequest('Cannot grant permissions you do not have'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should not create an api key with more permissions', async () => {
|
|
|
|
|
const { secret } = await create(user.accessToken, [Permission.ApiKeyCreate]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.post('/api-keys')
|
|
|
|
|
.set('x-api-key', secret)
|
|
|
|
|
.send({ name: 'API Key', permissions: [Permission.ApiKeyRead] });
|
|
|
|
|
expect(status).toBe(400);
|
|
|
|
|
expect(body).toEqual(errorDto.badRequest('Cannot grant permissions you do not have'));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should create an api key', async () => {
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.post('/api-keys')
|
|
|
|
|
.send({ name: 'API Key' })
|
|
|
|
|
.send({ name: 'API Key', permissions: [Permission.All] })
|
|
|
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
|
|
|
expect(body).toEqual({
|
|
|
|
|
apiKey: {
|
|
|
|
|
id: expect.any(String),
|
|
|
|
|
name: 'API Key',
|
|
|
|
|
permissions: [Permission.All],
|
|
|
|
|
createdAt: expect.any(String),
|
|
|
|
|
updatedAt: expect.any(String),
|
|
|
|
|
},
|
|
|
|
|
@@ -63,9 +113,9 @@ describe('/api-keys', () => {
|
|
|
|
|
|
|
|
|
|
it('should return a list of api keys', async () => {
|
|
|
|
|
const [{ apiKey: apiKey1 }, { apiKey: apiKey2 }, { apiKey: apiKey3 }] = await Promise.all([
|
|
|
|
|
create(admin.accessToken),
|
|
|
|
|
create(admin.accessToken),
|
|
|
|
|
create(admin.accessToken),
|
|
|
|
|
create(admin.accessToken, [Permission.All]),
|
|
|
|
|
create(admin.accessToken, [Permission.All]),
|
|
|
|
|
create(admin.accessToken, [Permission.All]),
|
|
|
|
|
]);
|
|
|
|
|
const { status, body } = await request(app).get('/api-keys').set('Authorization', `Bearer ${admin.accessToken}`);
|
|
|
|
|
expect(body).toHaveLength(3);
|
|
|
|
|
@@ -82,7 +132,7 @@ describe('/api-keys', () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should require authorization', async () => {
|
|
|
|
|
const { apiKey } = await create(user.accessToken);
|
|
|
|
|
const { apiKey } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.get(`/api-keys/${apiKey.id}`)
|
|
|
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
|
|
|
@@ -99,7 +149,7 @@ describe('/api-keys', () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should get api key details', async () => {
|
|
|
|
|
const { apiKey } = await create(user.accessToken);
|
|
|
|
|
const { apiKey } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.get(`/api-keys/${apiKey.id}`)
|
|
|
|
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
|
|
|
|
@@ -107,6 +157,7 @@ describe('/api-keys', () => {
|
|
|
|
|
expect(body).toEqual({
|
|
|
|
|
id: expect.any(String),
|
|
|
|
|
name: 'api key',
|
|
|
|
|
permissions: [Permission.All],
|
|
|
|
|
createdAt: expect.any(String),
|
|
|
|
|
updatedAt: expect.any(String),
|
|
|
|
|
});
|
|
|
|
|
@@ -121,7 +172,7 @@ describe('/api-keys', () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should require authorization', async () => {
|
|
|
|
|
const { apiKey } = await create(user.accessToken);
|
|
|
|
|
const { apiKey } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.put(`/api-keys/${apiKey.id}`)
|
|
|
|
|
.send({ name: 'new name' })
|
|
|
|
|
@@ -140,7 +191,7 @@ describe('/api-keys', () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should update api key details', async () => {
|
|
|
|
|
const { apiKey } = await create(user.accessToken);
|
|
|
|
|
const { apiKey } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.put(`/api-keys/${apiKey.id}`)
|
|
|
|
|
.send({ name: 'new name' })
|
|
|
|
|
@@ -149,6 +200,7 @@ describe('/api-keys', () => {
|
|
|
|
|
expect(body).toEqual({
|
|
|
|
|
id: expect.any(String),
|
|
|
|
|
name: 'new name',
|
|
|
|
|
permissions: [Permission.All],
|
|
|
|
|
createdAt: expect.any(String),
|
|
|
|
|
updatedAt: expect.any(String),
|
|
|
|
|
});
|
|
|
|
|
@@ -163,7 +215,7 @@ describe('/api-keys', () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should require authorization', async () => {
|
|
|
|
|
const { apiKey } = await create(user.accessToken);
|
|
|
|
|
const { apiKey } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status, body } = await request(app)
|
|
|
|
|
.delete(`/api-keys/${apiKey.id}`)
|
|
|
|
|
.set('Authorization', `Bearer ${admin.accessToken}`);
|
|
|
|
|
@@ -180,7 +232,7 @@ describe('/api-keys', () => {
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should delete an api key', async () => {
|
|
|
|
|
const { apiKey } = await create(user.accessToken);
|
|
|
|
|
const { apiKey } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status } = await request(app)
|
|
|
|
|
.delete(`/api-keys/${apiKey.id}`)
|
|
|
|
|
.set('Authorization', `Bearer ${user.accessToken}`);
|
|
|
|
|
@@ -190,14 +242,14 @@ describe('/api-keys', () => {
|
|
|
|
|
|
|
|
|
|
describe('authentication', () => {
|
|
|
|
|
it('should work as a header', async () => {
|
|
|
|
|
const { secret } = await create(admin.accessToken);
|
|
|
|
|
const { secret } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status, body } = await request(app).get('/api-keys').set('x-api-key', secret);
|
|
|
|
|
expect(body).toHaveLength(1);
|
|
|
|
|
expect(status).toBe(200);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it('should work as a query param', async () => {
|
|
|
|
|
const { secret } = await create(admin.accessToken);
|
|
|
|
|
const { secret } = await create(user.accessToken, [Permission.All]);
|
|
|
|
|
const { status, body } = await request(app).get(`/api-keys?apiKey=${secret}`);
|
|
|
|
|
expect(body).toHaveLength(1);
|
|
|
|
|
expect(status).toBe(200);
|
|
|
|
|
|