Skip to content

Commit 9cf0619

Browse files
authored
Merge branch 'main' into totp-mfa-unenroll
2 parents 2ca0662 + 65b4f41 commit 9cf0619

File tree

316 files changed

+12685
-16427
lines changed

Some content is hidden

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

316 files changed

+12685
-16427
lines changed

.github/workflows/create_test_patches.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
timeout_minutes: 15
5252
retry_wait_seconds: 60
5353
max_attempts: 3
54-
command: DETOX_DISABLE_POSTINSTALL=1 yarn && yarn lerna:prepare
54+
command: DETOX_DISABLE_POSTINSTALL=1 yarn
5555

5656
- name: Create Patches
5757
env:

.github/workflows/linting.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
timeout_minutes: 15
4444
retry_wait_seconds: 30
4545
max_attempts: 3
46-
command: yarn && yarn lerna:prepare
46+
command: yarn
4747
- name: Lint
4848
uses: nick-fields/retry@v3
4949
with:
@@ -83,7 +83,7 @@ jobs:
8383
timeout_minutes: 15
8484
retry_wait_seconds: 30
8585
max_attempts: 3
86-
command: yarn && yarn lerna:prepare
86+
command: yarn
8787
- name: Lint
8888
run: yarn tsc:compile
8989
- uses: actions/cache/save@v4
@@ -118,7 +118,7 @@ jobs:
118118
timeout_minutes: 15
119119
retry_wait_seconds: 30
120120
max_attempts: 3
121-
command: yarn && yarn lerna:prepare
121+
command: yarn
122122
- name: Yarn Install (Website)
123123
uses: nick-fields/retry@v3
124124
with:

.github/workflows/publish.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ jobs:
3030
timeout_minutes: 15
3131
retry_wait_seconds: 60
3232
max_attempts: 3
33-
command: yarn && yarn lerna:prepare
33+
command: yarn
3434
- name: GIT Setup
3535
# Alter branding of release commit, despite GITHUB_TOKEN having real owner
3636
run: |

.github/workflows/scripts/functions/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@
99
"logs": "firebase functions:log"
1010
},
1111
"engines": {
12-
"node": "18"
12+
"node": "22"
1313
},
1414
"main": "lib/index.js",
1515
"dependencies": {
1616
"firebase-admin": "^13.4.0",
17-
"firebase-functions": "^6.3.2"
17+
"firebase-functions": "^6.4.0"
1818
},
1919
"devDependencies": {
2020
"firebase-functions-test": "^3.4.1",
21-
"firebase-tools": "^14.9.0",
22-
"typescript": "^5.8.3"
21+
"firebase-tools": "^14.14.0",
22+
"typescript": "^5.9.2"
2323
},
2424
"private": true
2525
}

.github/workflows/scripts/functions/src/fetchAppCheckToken.ts

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,15 @@
77
* See License file for more information.
88
*/
99

10-
import * as admin from 'firebase-admin';
11-
import * as functions from 'firebase-functions/v2';
12-
import { CallableRequest } from 'firebase-functions/v2/https';
10+
import { getAppCheck } from 'firebase-admin/app-check';
11+
import { CallableRequest, onCall } from 'firebase-functions/v2/https';
12+
import { getAdminApp } from '.';
1313

1414
// Note: this will only work in a live environment, not locally via the Firebase emulator.
15-
export const fetchAppCheckTokenV2 = functions.https.onCall(
16-
async (req: CallableRequest<{ appId: string }>) => {
17-
const { appId } = req.data;
18-
const expireTimeMillis = Math.floor(Date.now() / 1000) + 60 * 60;
19-
const result = await admin.appCheck().createToken(appId);
20-
return { ...result, expireTimeMillis };
21-
},
22-
);
15+
export const fetchAppCheckTokenV2 = onCall(async (req: CallableRequest<{ appId: string }>) => {
16+
const { appId } = req.data;
17+
const expireTimeMillis = Math.floor(Date.now() / 1000) + 60 * 60;
18+
getAdminApp();
19+
const result = await getAppCheck().createToken(appId);
20+
return { ...result, expireTimeMillis };
21+
});

.github/workflows/scripts/functions/src/index.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,28 @@
1-
import * as functions from 'firebase-functions/v2';
2-
import { CallableRequest } from 'firebase-functions/v2/https';
1+
import { App, initializeApp } from 'firebase-admin/app';
2+
import { logger } from 'firebase-functions/v2';
3+
import { CallableRequest, onRequest, onCall } from 'firebase-functions/v2/https';
34

4-
// // Start writing Firebase Functions
5-
// // https://firebase.google.com/docs/functions/typescript
6-
//
7-
export const helloWorldV2 = functions.https.onRequest((_, response) => {
8-
functions.logger.info('Hello logs!', { structuredData: true });
5+
let _app: App;
6+
7+
export function getAdminApp(): App {
8+
if (!_app) {
9+
_app = initializeApp();
10+
}
11+
return _app;
12+
}
13+
14+
export const helloWorldV2 = onRequest((_, response) => {
15+
logger.info('Hello logs!', { structuredData: true });
916
response.send('{ "data": "Hello from Firebase!" }');
1017
});
1118

12-
export const sleeperV2 = functions.https.onCall(
13-
async (req: CallableRequest<{ delay?: number }>) => {
14-
functions.logger.info('Sleeper function starting');
15-
return await new Promise(() => {
16-
functions.logger.info('Sleeping this long: ' + (req.data.delay ?? 3000));
17-
setTimeout(() => functions.logger.info('done sleeping'), req.data.delay ?? 3000);
18-
});
19-
},
20-
);
19+
export const sleeperV2 = onCall(async (req: CallableRequest<{ delay?: number }>) => {
20+
logger.info('Sleeper function starting');
21+
return await new Promise(() => {
22+
logger.info('Sleeping this long: ' + (req.data.delay ?? 3000));
23+
setTimeout(() => logger.info('done sleeping'), req.data.delay ?? 3000);
24+
});
25+
});
2126

2227
export { testFunctionCustomRegion } from './testFunctionCustomRegion';
2328
export { testFunctionDefaultRegionV2 } from './testFunctionDefaultRegion';

.github/workflows/scripts/functions/src/sendFCM.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,18 @@
77
* See License file for more information.
88
*/
99

10-
import * as functions from 'firebase-functions/v2';
11-
import { CallableRequest } from 'firebase-functions/v2/https';
12-
10+
import { logger } from 'firebase-functions/v2';
11+
import { CallableRequest, onCall } from 'firebase-functions/v2/https';
1312
import { getMessaging, TokenMessage } from 'firebase-admin/messaging';
1413

1514
// Note: this will only work in a live environment, not locally via the Firebase emulator.
16-
export const sendFCM = functions.https.onCall(
15+
export const sendFCM = onCall(
1716
async (req: CallableRequest<{ message: TokenMessage; delay?: number }>) => {
1817
const { message, delay } = req.data;
1918
return await new Promise(() => {
20-
functions.logger.info('Sleeping this many milliseconds: ' + (delay ?? 0));
19+
logger.info('Sleeping this many milliseconds: ' + (delay ?? 0));
2120
setTimeout(async () => {
22-
functions.logger.info('done sleeping');
21+
logger.info('done sleeping');
2322
const result = await getMessaging().send(message);
2423
return { messageId: result };
2524
}, delay ?? 0);

.github/workflows/scripts/functions/src/testFunctionCustomRegion.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@
77
* See License file for more information.
88
*/
99

10-
import * as functions from 'firebase-functions/v1';
10+
import { onCall } from 'firebase-functions/v2/https';
1111

12-
// stay v1 here - v2 functions don't support custom regions well,
13-
// they require httpsCallableFromUrl which is tested separately
14-
export const testFunctionCustomRegion = functions
15-
.region('europe-west1')
16-
.https.onCall(() => 'europe-west1');
12+
export const testFunctionCustomRegion = onCall(
13+
{
14+
region: 'europe-west1',
15+
},
16+
() => 'europe-west1',
17+
);

.github/workflows/scripts/functions/src/testFunctionDefaultRegion.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
* See License file for more information.
88
*/
99

10-
import * as assert from 'assert';
10+
import { deepEqual } from 'assert';
1111
import { FirebaseError } from 'firebase-admin';
12-
import * as functions from 'firebase-functions/v2';
12+
import { CallableRequest, onCall, HttpsError } from 'firebase-functions/v2/https';
1313
import SAMPLE_DATA from './sample-data';
14-
import { CallableRequest } from 'firebase-functions/v2/https';
1514

16-
export const testFunctionDefaultRegionV2 = functions.https.onCall(
15+
export const testFunctionDefaultRegionV2 = onCall(
1716
(req: CallableRequest<{ type: string; asError: boolean; inputData: any }>) => {
1817
console.log(Date.now(), req.data);
1918

@@ -43,16 +42,16 @@ export const testFunctionDefaultRegionV2 = functions.https.onCall(
4342

4443
const { type, asError, inputData } = req.data;
4544
if (!Object.hasOwnProperty.call(SAMPLE_DATA, type)) {
46-
throw new functions.https.HttpsError('invalid-argument', 'Invalid test requested.');
45+
throw new HttpsError('invalid-argument', 'Invalid test requested.');
4746
}
4847

4948
const outputData = SAMPLE_DATA[type];
5049

5150
try {
52-
assert.deepEqual(outputData, inputData);
51+
deepEqual(outputData, inputData);
5352
} catch (e) {
5453
console.error(e);
55-
throw new functions.https.HttpsError(
54+
throw new HttpsError(
5655
'invalid-argument',
5756
'Input and Output types did not match.',
5857
(e as FirebaseError).message,
@@ -61,7 +60,7 @@ export const testFunctionDefaultRegionV2 = functions.https.onCall(
6160

6261
// all good
6362
if (asError) {
64-
throw new functions.https.HttpsError(
63+
throw new HttpsError(
6564
'cancelled',
6665
'Response data was requested to be sent as part of an Error payload, so here we are!',
6766
outputData,

.github/workflows/scripts/functions/src/testFunctionRemoteConfigUpdate.ts

Lines changed: 57 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,18 @@
66
*
77
* See License file for more information.
88
*/
9-
import * as admin from 'firebase-admin';
10-
import * as functions from 'firebase-functions/v2';
11-
import { CallableRequest } from 'firebase-functions/v2/https';
9+
// import * as admin from 'firebase-admin';
10+
import { getRemoteConfig } from 'firebase-admin/remote-config';
11+
import { logger } from 'firebase-functions/v2';
12+
import { CallableRequest, onCall } from 'firebase-functions/v2/https';
13+
import { getAdminApp } from '.';
1214

13-
admin.initializeApp();
14-
const remoteConfig = admin.remoteConfig();
15-
16-
export const testFunctionRemoteConfigUpdateV2 = functions.https.onCall(
17-
(
15+
export const testFunctionRemoteConfigUpdateV2 = onCall(
16+
{
17+
maxInstances: 1,
18+
concurrency: 1,
19+
},
20+
async (
1821
req: CallableRequest<{
1922
operations: {
2023
delete: string[] | undefined;
@@ -23,61 +26,55 @@ export const testFunctionRemoteConfigUpdateV2 = functions.https.onCall(
2326
};
2427
}>,
2528
) => {
26-
console.log(Date.now(), req);
29+
let template = await getRemoteConfig(getAdminApp()).getTemplate();
30+
logger.info('received template version: ' + JSON.stringify(template.version));
31+
// logger.info('received template: ' + JSON.stringify(template, null, 2));
32+
33+
if (req.data !== undefined && req.data.operations !== undefined) {
34+
modifyTemplate(req.data, template);
35+
}
2736

28-
return new Promise(function (resolve, reject) {
29-
remoteConfig
30-
.getTemplate()
31-
.then((template: any) => {
32-
console.log('received template version: ' + JSON.stringify(template.version));
33-
// console.log('received template: ' + JSON.stringify(template, null, 2));
37+
// validate the template
38+
template = await getRemoteConfig(getAdminApp()).validateTemplate(template);
39+
logger.info('template is valid after updates.');
40+
template = await getRemoteConfig(getAdminApp()).publishTemplate(template);
41+
logger.info('template published, new version: ' + JSON.stringify(template.version));
3442

35-
if (req.data?.operations['delete'] !== undefined) {
36-
const deletions = req.data?.operations['delete'];
37-
deletions.forEach((deletion: string) => {
38-
console.log('deleting key: ' + deletion);
39-
if (template.parameters?.deletion !== undefined) {
40-
delete template.parameters.deletion;
41-
}
42-
});
43-
}
43+
return { templateVersion: template.version?.versionNumber };
44+
},
45+
);
4446

45-
if (req.data?.operations['add'] !== undefined) {
46-
const adds = req.data?.operations['add'];
47-
adds.forEach((add: { name: string; value: any }) => {
48-
console.log('adding key: ' + JSON.stringify(add));
49-
template.parameters[add.name] = {
50-
description: 'realtime test parameter',
51-
defaultValue: {
52-
value: add.value,
53-
},
54-
};
55-
});
56-
}
47+
function modifyTemplate(data: any, template: any) {
48+
if (data.operations['delete'] !== undefined) {
49+
const deletions = data.operations['delete'];
50+
deletions.forEach((deletion: string) => {
51+
logger.info('deleting key: ' + deletion);
52+
if (template.parameters[deletion] !== undefined) {
53+
delete template.parameters[deletion];
54+
}
55+
});
56+
}
5757

58-
if (req.data?.operations['update'] !== undefined) {
59-
const updates = req.data?.operations['update'];
60-
updates.forEach((update: { name: string; value: any }) => {
61-
console.log('updating key: ' + JSON.stringify(update));
62-
if (template.parameters[update.name] !== undefined) {
63-
template.parameters[update.name].defaultValue = update.value;
64-
}
65-
});
66-
}
58+
if (data.operations['add'] !== undefined) {
59+
const adds = data.operations['add'];
60+
adds.forEach((add: { name: string; value: any }) => {
61+
logger.info('adding key: ' + JSON.stringify(add));
62+
template.parameters[add.name] = {
63+
description: 'realtime test parameter',
64+
defaultValue: {
65+
value: add.value,
66+
},
67+
};
68+
});
69+
}
6770

68-
// validate the template
69-
remoteConfig.validateTemplate(template).then(template => {
70-
console.log('template is valid after updates.');
71-
remoteConfig.publishTemplate(template).then(template => {
72-
console.log('template published, new version: ' + JSON.stringify(template.version));
73-
resolve({ templateVersion: template.version?.versionNumber });
74-
});
75-
});
76-
})
77-
.catch((err: string) => {
78-
console.error('remoteConfig.getTemplate failure: ' + err);
79-
reject({ status: 'failure', message: err });
80-
});
71+
if (data.operations['update'] !== undefined) {
72+
const updates = data.operations['update'];
73+
updates.forEach((update: { name: string; value: any }) => {
74+
logger.info('updating key: ' + JSON.stringify(update));
75+
if (template.parameters[update.name] !== undefined) {
76+
template.parameters[update.name].defaultValue = update.value;
77+
}
8178
});
82-
},
83-
);
79+
}
80+
}

0 commit comments

Comments
 (0)