Add origin to accountability (#15273)

* Add origin to accountability

* Remove origin column from seeds
This commit is contained in:
ian
2022-08-31 02:15:44 +08:00
committed by GitHub
parent b2d127dcc8
commit a971455216
22 changed files with 111 additions and 4 deletions

View File

@@ -373,6 +373,7 @@ export function createLDAPAuthRouter(provider: string): Router {
const accountability = {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
};

View File

@@ -62,6 +62,7 @@ export function createLocalAuthRouter(provider: string): Router {
const accountability = {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
};

View File

@@ -276,6 +276,7 @@ export function createOAuth2AuthRouter(providerName: string): Router {
accountability: {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
},
schema: req.schema,

View File

@@ -300,6 +300,7 @@ export function createOpenIDAuthRouter(providerName: string): Router {
accountability: {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
},
schema: req.schema,

View File

@@ -92,6 +92,7 @@ router.post(
user: req.accountability?.user,
ip: getIPFromReq(req),
user_agent: req.get('user-agent'),
origin: req.get('origin'),
});
try {

View File

@@ -59,6 +59,7 @@ router.post(
const accountability = {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
};
@@ -101,6 +102,7 @@ router.post(
const accountability = {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
};
@@ -141,6 +143,7 @@ router.post(
const accountability = {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
};
@@ -175,6 +178,7 @@ router.post(
const accountability = {
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
role: null,
};

View File

@@ -0,0 +1,21 @@
import { Knex } from 'knex';
export async function up(knex: Knex): Promise<void> {
await knex.schema.alterTable('directus_activity', (table) => {
table.string('origin').nullable();
});
await knex.schema.alterTable('directus_sessions', (table) => {
table.string('origin').nullable();
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.alterTable('directus_activity', (table) => {
table.dropColumn('origin');
});
await knex.schema.alterTable('directus_sessions', (table) => {
table.dropColumn('origin');
});
}

View File

@@ -60,6 +60,12 @@ fields:
font: monospace
width: half
- field: origin
display: formatted-value
display_options:
font: monospace
width: half
- field: ip
display: formatted-value
display_options:

View File

@@ -11,4 +11,6 @@ fields:
width: half
- field: user_agent
width: half
- field: origin
width: half
- field: share

View File

@@ -331,6 +331,7 @@ class FlowManager {
collection: 'directus_flows',
ip: accountability?.ip ?? null,
user_agent: accountability?.userAgent ?? null,
origin: accountability?.origin ?? null,
item: flow.id,
});

View File

@@ -39,7 +39,16 @@ test('Short-circuits when authenticate filter is used', async () => {
test('Uses default public accountability when no token is given', async () => {
const req = {
ip: '127.0.0.1',
get: jest.fn((string) => (string === 'user-agent' ? 'fake-user-agent' : null)),
get: jest.fn((string) => {
switch (string) {
case 'user-agent':
return 'fake-user-agent';
case 'origin':
return 'fake-origin';
default:
return null;
}
}),
};
const res = {};
@@ -56,6 +65,7 @@ test('Uses default public accountability when no token is given', async () => {
app: false,
ip: '127.0.0.1',
userAgent: 'fake-user-agent',
origin: 'fake-origin',
});
expect(next).toHaveBeenCalledTimes(1);
@@ -87,7 +97,16 @@ test('Sets accountability to payload contents if valid token is passed', async (
const req = {
ip: '127.0.0.1',
get: jest.fn((string) => (string === 'user-agent' ? 'fake-user-agent' : null)),
get: jest.fn((string) => {
switch (string) {
case 'user-agent':
return 'fake-user-agent';
case 'origin':
return 'fake-origin';
default:
return null;
}
}),
token,
};
@@ -105,6 +124,7 @@ test('Sets accountability to payload contents if valid token is passed', async (
share_scope: shareScope,
ip: '127.0.0.1',
userAgent: 'fake-user-agent',
origin: 'fake-origin',
});
expect(next).toHaveBeenCalledTimes(1);
@@ -136,6 +156,7 @@ test('Sets accountability to payload contents if valid token is passed', async (
share_scope: shareScope,
ip: '127.0.0.1',
userAgent: 'fake-user-agent',
origin: 'fake-origin',
});
expect(next).toHaveBeenCalledTimes(1);
@@ -152,7 +173,16 @@ test('Throws InvalidCredentialsException when static token is used, but user doe
const req = {
ip: '127.0.0.1',
get: jest.fn((string) => (string === 'user-agent' ? 'fake-user-agent' : null)),
get: jest.fn((string) => {
switch (string) {
case 'user-agent':
return 'fake-user-agent';
case 'origin':
return 'fake-origin';
default:
return null;
}
}),
token: 'static-token',
};
@@ -166,7 +196,16 @@ test('Throws InvalidCredentialsException when static token is used, but user doe
test('Sets accountability to user information when static token is used', async () => {
const req = {
ip: '127.0.0.1',
get: jest.fn((string) => (string === 'user-agent' ? 'fake-user-agent' : null)),
get: jest.fn((string) => {
switch (string) {
case 'user-agent':
return 'fake-user-agent';
case 'origin':
return 'fake-origin';
default:
return null;
}
}),
token: 'static-token',
};
@@ -182,6 +221,7 @@ test('Sets accountability to user information when static token is used', async
admin: testUser.admin_access,
ip: '127.0.0.1',
userAgent: 'fake-user-agent',
origin: 'fake-origin',
};
jest.mocked(getDatabase).mockReturnValue({

View File

@@ -21,6 +21,7 @@ export const handler = async (req: Request, res: Response, next: NextFunction) =
app: false,
ip: getIPFromReq(req),
userAgent: req.get('user-agent'),
origin: req.get('origin'),
};
const database = getDatabase();

View File

@@ -216,6 +216,7 @@ export class AuthenticationService {
expires: refreshTokenExpiration,
ip: this.accountability?.ip,
user_agent: this.accountability?.userAgent,
origin: this.accountability?.origin,
});
await this.knex('directus_sessions').delete().where('expires', '<', new Date());
@@ -226,6 +227,7 @@ export class AuthenticationService {
user: user.id,
ip: this.accountability.ip,
user_agent: this.accountability.userAgent,
origin: this.accountability.origin,
collection: 'directus_users',
item: user.id,
});

View File

@@ -1955,6 +1955,7 @@ export class GraphQLService {
const accountability = {
ip: req?.ip,
userAgent: req?.get('user-agent'),
origin: req?.get('origin'),
role: null,
};
const authenticationService = new AuthenticationService({
@@ -1988,6 +1989,7 @@ export class GraphQLService {
const accountability = {
ip: req?.ip,
userAgent: req?.get('user-agent'),
origin: req?.get('origin'),
role: null,
};
const authenticationService = new AuthenticationService({
@@ -2024,6 +2026,7 @@ export class GraphQLService {
const accountability = {
ip: req?.ip,
userAgent: req?.get('user-agent'),
origin: req?.get('origin'),
role: null,
};
const authenticationService = new AuthenticationService({
@@ -2048,6 +2051,7 @@ export class GraphQLService {
const accountability = {
ip: req?.ip,
userAgent: req?.get('user-agent'),
origin: req?.get('origin'),
role: null,
};
const service = new UsersService({ accountability, schema: this.schema });
@@ -2073,6 +2077,7 @@ export class GraphQLService {
const accountability = {
ip: req?.ip,
userAgent: req?.get('user-agent'),
origin: req?.get('origin'),
role: null,
};
const service = new UsersService({ accountability, schema: this.schema });
@@ -2680,6 +2685,7 @@ export class GraphQLService {
user: this.accountability?.user,
ip: this.accountability?.ip,
user_agent: this.accountability?.userAgent,
origin: this.accountability?.origin,
});
if ('directus_activity' in ReadCollectionTypes) {

View File

@@ -185,6 +185,7 @@ export class ItemsService<Item extends AnyItem = AnyItem> implements AbstractSer
collection: this.collection,
ip: this.accountability!.ip,
user_agent: this.accountability!.userAgent,
origin: this.accountability!.origin,
item: primaryKey,
});
@@ -549,6 +550,7 @@ export class ItemsService<Item extends AnyItem = AnyItem> implements AbstractSer
collection: this.collection,
ip: this.accountability!.ip,
user_agent: this.accountability!.userAgent,
origin: this.accountability!.origin,
item: key,
}))
);
@@ -763,6 +765,7 @@ export class ItemsService<Item extends AnyItem = AnyItem> implements AbstractSer
collection: this.collection,
ip: this.accountability!.ip,
user_agent: this.accountability!.userAgent,
origin: this.accountability!.origin,
item: key,
}))
);

View File

@@ -101,6 +101,7 @@ export class SharesService extends ItemsService {
expires: refreshTokenExpiration,
ip: this.accountability?.ip,
user_agent: this.accountability?.userAgent,
origin: this.accountability?.origin,
share: record.share_id,
});

View File

@@ -79,6 +79,7 @@ export function useRevisions(collection: Ref<string>, primaryKey: Ref<number | s
'activity.user.last_name',
'activity.ip',
'activity.user_agent',
'activity.origin',
],
meta: ['filter_count'],
},
@@ -115,6 +116,7 @@ export function useRevisions(collection: Ref<string>, primaryKey: Ref<number | s
'activity.user.last_name',
'activity.ip',
'activity.user_agent',
'activity.origin',
],
meta: ['filter_count'],
},

View File

@@ -543,6 +543,7 @@ activity_item: Activity Item
action: Action
ip_address: IP Address
user_agent: User Agent
origin: Origin
webhooks: Webhooks
decimals: Decimals
value_decimals: Value Decimals
@@ -1056,6 +1057,7 @@ fields:
user: Action By
comment: Comment
user_agent: User Agent
origin: Origin
ip: IP Address
revisions: Revisions
directus_collections:

View File

@@ -27,6 +27,9 @@
<p class="type-label">{{ t('user_agent') }}:</p>
<p>{{ item.user_agent }}</p>
<p class="type-label">{{ t('origin') }}:</p>
<p>{{ item.origin }}</p>
<p class="type-label">{{ t('collection') }}:</p>
<p>{{ item.collection }}</p>
@@ -62,6 +65,7 @@ type ActivityRecord = {
timestamp: string;
ip: string;
user_agent: string;
origin: string;
collection: string;
item: string;
};
@@ -109,6 +113,7 @@ export default defineComponent({
'timestamp',
'ip',
'user_agent',
'origin',
'collection',
'item',
],

View File

@@ -8,6 +8,7 @@ export type Revision = {
action: string;
ip: string;
user_agent: string;
origin: string;
timestamp: string;
user:
| string

View File

@@ -16,4 +16,5 @@ export type Accountability = {
ip?: string;
userAgent?: string;
origin?: string;
};

View File

@@ -37,6 +37,10 @@ properties:
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/78.0.3904.108
Safari/537.36
type: string
origin:
description: Origin of the request when the action took place.
example: https://directus.io
type: string
collection:
description: Collection identifier in which the item resides.
oneOf: