Skip to content

Commit 5d2d5bf

Browse files
committed
Merge branch 'upstream/header-based-auth' into release52
# Conflicts: # meteor/server/api/evaluations.ts # meteor/server/migration/api.ts # meteor/server/publications/blueprintUpgradeStatus/publication.ts # meteor/server/publications/system.ts
2 parents 263a06c + 4c7a337 commit 5d2d5bf

File tree

131 files changed

+1846
-4693
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

131 files changed

+1846
-4693
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ meteor/.coverage/
44
node_modules
55
**/yarn-error.log
66
scratch/
7+
meteor-settings.json
78

89
# Exclude JetBrains IDE specific files
910
.idea

meteor/.meteor/packages

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,4 @@ [email protected] # Enable TypeScript syntax in .ts and .tsx modules
1919

2020
[email protected] # Meteor's client-side reactive programming library
2121

22-
23-
2422
zodern:types

meteor/__mocks__/_setupMocks.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ jest.mock('meteor/meteor', (...args) => require('./meteor').setup(args), { virtu
1414
jest.mock('meteor/random', (...args) => require('./random').setup(args), { virtual: true })
1515
jest.mock('meteor/check', (...args) => require('./check').setup(args), { virtual: true })
1616
jest.mock('meteor/tracker', (...args) => require('./tracker').setup(args), { virtual: true })
17-
jest.mock('meteor/accounts-base', (...args) => require('./accounts-base').setup(args), { virtual: true })
1817
jest.mock('meteor/ejson', (...args) => require('./ejson').setup(args), { virtual: true })
1918

2019
jest.mock('meteor/mdg:validated-method', (...args) => require('./validated-method').setup(args), { virtual: true })

meteor/__mocks__/accounts-base.ts

Lines changed: 0 additions & 81 deletions
This file was deleted.

meteor/__mocks__/meteor.ts

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { MongoMock } from './mongo'
1+
import { USER_PERMISSIONS_HEADER } from '@sofie-automation/meteor-lib/dist/userPermissions'
22

33
let controllableDefer = false
44

@@ -9,27 +9,14 @@ export function useNextTickDefer(): void {
99
controllableDefer = false
1010
}
1111

12-
namespace Meteor {
12+
export namespace Meteor {
1313
export interface Settings {
1414
public: {
1515
[id: string]: any
1616
}
1717
[id: string]: any
1818
}
1919

20-
export interface UserEmail {
21-
address: string
22-
verified: boolean
23-
}
24-
export interface User {
25-
_id?: string
26-
username?: string
27-
emails?: UserEmail[]
28-
createdAt?: number
29-
profile?: any
30-
services?: any
31-
}
32-
3320
export interface ErrorStatic {
3421
new (error: string | number, reason?: string, details?: string): Error
3522
}
@@ -103,22 +90,18 @@ export namespace MeteorMock {
10390
export const settings: any = {}
10491

10592
export const mockMethods: { [name: string]: Function } = {}
106-
export let mockUser: Meteor.User | undefined = undefined
10793
export const mockStartupFunctions: Function[] = []
10894

10995
export const absolutePath = process.cwd()
11096

111-
export function user(): Meteor.User | undefined {
112-
return mockUser
113-
}
114-
export function userId(): string | undefined {
115-
return mockUser ? mockUser._id : undefined
116-
}
11797
function getMethodContext() {
11898
return {
119-
userId: mockUser ? mockUser._id : undefined,
12099
connection: {
121100
clientAddress: '1.1.1.1',
101+
httpHeaders: {
102+
// Default to full permissions for tests
103+
[USER_PERMISSIONS_HEADER]: 'admin',
104+
},
122105
},
123106
unblock: () => {
124107
// noop
@@ -256,7 +239,6 @@ export namespace MeteorMock {
256239
return fcn(...args)
257240
}
258241
}
259-
export let users: MongoMock.Collection<any> | undefined = undefined
260242

261243
// -- Mock functions: --------------------------
262244
/**
@@ -269,12 +251,6 @@ export namespace MeteorMock {
269251

270252
await waitTimeNoFakeTimers(10) // So that any observers or defers has had time to run.
271253
}
272-
export function mockLoginUser(newUser: Meteor.User): void {
273-
mockUser = newUser
274-
}
275-
export function mockSetUsersCollection(usersCollection: MongoMock.Collection<any>): void {
276-
users = usersCollection
277-
}
278254
export function mockSetClientEnvironment(): void {
279255
mockIsClient = true
280256
}

meteor/__mocks__/mongo.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -453,5 +453,3 @@ export function setup(): any {
453453
Mongo: MongoMock,
454454
}
455455
}
456-
457-
MeteorMock.mockSetUsersCollection(new MongoMock.Collection('Meteor.users'))

meteor/server/Connections.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { logger } from './logging'
44
import { sendTrace } from './api/integration/influx'
55
import { PeripheralDevices } from './collections'
66
import { MetricsGauge } from '@sofie-automation/corelib/dist/prometheus'
7+
import { parseUserPermissions, USER_PERMISSIONS_HEADER } from '@sofie-automation/meteor-lib/dist/userPermissions'
8+
import { Settings } from './Settings'
79

810
const connections = new Set<string>()
911
const connectionsGauge = new MetricsGauge({
@@ -14,6 +16,24 @@ const connectionsGauge = new MetricsGauge({
1416
Meteor.onConnection((conn: Meteor.Connection) => {
1517
// This is called whenever a new ddp-connection is opened (ie a web-client or a peripheral-device)
1618

19+
if (Settings.enableHeaderAuth) {
20+
const userLevel = parseUserPermissions(conn.httpHeaders[USER_PERMISSIONS_HEADER])
21+
22+
// HACK: force the userId of the connection before it can be used.
23+
// This ensures we know the permissions of the connection before it can try to do anything
24+
// This could probably be safely done inside a meteor method, as we only need it when directly modifying a collection in the client,
25+
// but that will cause all the publications to restart when changing the userId.
26+
const connSession = (Meteor as any).server.sessions.get(conn.id)
27+
if (!connSession) {
28+
logger.error(`Failed to find session for ddp connection! "${conn.id}"`)
29+
// Close the connection, it won't be secure
30+
conn.close()
31+
return
32+
} else {
33+
connSession.userId = JSON.stringify(userLevel)
34+
}
35+
}
36+
1737
const connectionId: string = conn.id
1838
// var clientAddress = conn.clientAddress; // ip-adress
1939

meteor/server/__tests__/cronjobs.test.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -476,7 +476,8 @@ describe('cronjobs', () => {
476476
expect(await Snapshots.findOneAsync(snapshot1)).toBeUndefined()
477477
})
478478
async function insertPlayoutDevice(
479-
props: Pick<PeripheralDevice, 'subType' | 'deviceName' | 'lastSeen' | 'parentDeviceId'>
479+
props: Pick<PeripheralDevice, 'subType' | 'deviceName' | 'lastSeen' | 'parentDeviceId'> &
480+
Partial<Pick<PeripheralDevice, 'token'>>
480481
): Promise<PeripheralDeviceId> {
481482
const deviceId = protectString<PeripheralDeviceId>(getRandomString())
482483
await PeripheralDevices.insertAsync({
@@ -505,37 +506,43 @@ describe('cronjobs', () => {
505506
}
506507

507508
async function createMockPlayoutGatewayAndDevices(lastSeen: number): Promise<{
509+
deviceToken: string
508510
mockPlayoutGw: PeripheralDeviceId
509511
mockCasparCg: PeripheralDeviceId
510512
mockAtem: PeripheralDeviceId
511513
}> {
514+
const deviceToken = 'token1'
512515
const mockPlayoutGw = await insertPlayoutDevice({
513516
deviceName: 'Playout Gateway',
514517
lastSeen: lastSeen,
515518
subType: PERIPHERAL_SUBTYPE_PROCESS,
519+
token: deviceToken,
516520
})
517521
const mockCasparCg = await insertPlayoutDevice({
518522
deviceName: 'CasparCG',
519523
lastSeen: lastSeen,
520524
subType: TSR.DeviceType.CASPARCG,
521525
parentDeviceId: mockPlayoutGw,
526+
token: deviceToken,
522527
})
523528
const mockAtem = await insertPlayoutDevice({
524529
deviceName: 'ATEM',
525530
lastSeen: lastSeen,
526531
subType: TSR.DeviceType.ATEM,
527532
parentDeviceId: mockPlayoutGw,
533+
token: deviceToken,
528534
})
529535

530536
return {
537+
deviceToken,
531538
mockPlayoutGw,
532539
mockCasparCg,
533540
mockAtem,
534541
}
535542
}
536543

537544
test('Attempts to restart CasparCG when job is enabled', async () => {
538-
const { mockCasparCg } = await createMockPlayoutGatewayAndDevices(Date.now()) // Some time after the threshold
545+
const { mockCasparCg, deviceToken } = await createMockPlayoutGatewayAndDevices(Date.now()) // Some time after the threshold
539546

540547
;(logger.info as jest.Mock).mockClear()
541548
// set time to 2020/07/{date} 04:05 Local Time, should be more than 24 hours after 2020/07/19 00:00 UTC
@@ -558,7 +565,7 @@ describe('cronjobs', () => {
558565
Meteor.callAsync(
559566
'peripheralDevice.functionReply',
560567
cmd.deviceId, // deviceId
561-
'', // deviceToken
568+
deviceToken, // deviceToken
562569
cmd._id, // commandId
563570
null, // err
564571
null // result

0 commit comments

Comments
 (0)