Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit 7c7c02d

Browse files
Validate Analytics keys and params #1339
1 parent 7ae32c6 commit 7c7c02d

File tree

8 files changed

+132
-27
lines changed

8 files changed

+132
-27
lines changed

demo-ng/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
"nativescript-angular": "^6.1.0",
2626
"nativescript-camera": "~4.1.1",
2727
"nativescript-imagepicker": "~6.0.5",
28-
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.3.tgz",
28+
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.4.tgz",
2929
"nativescript-theme-core": "~1.0.4",
3030
"reflect-metadata": "~0.1.10",
3131
"rxjs": "~6.0.0 || >=6.1.0",

demo-push/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
}
1010
},
1111
"dependencies": {
12-
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.3.tgz",
12+
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.4.tgz",
1313
"nativescript-theme-core": "^1.0.4",
1414
"nativescript-unit-test-runner": "^0.3.4",
1515
"tns-core-modules": "~4.2.0"

demo-vue/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
}
1515
},
1616
"dependencies": {
17-
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.3.tgz",
17+
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.4.tgz",
1818
"nativescript-theme-core": "^1.0.4",
1919
"nativescript-vue": "^2.0.0",
2020
"tns-core-modules": "^5.0.2"

demo/app/main-view-model.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -466,10 +466,11 @@ export class HelloWorldModel extends Observable {
466466
firebase.analytics.logEvent({
467467
// see https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event.html
468468
key: "add_to_cart",
469-
parameters: [{ // optional
470-
key: "item_id",
471-
value: "p7655"
472-
},
469+
parameters: [
470+
{ // optional
471+
key: "item_id",
472+
value: "p7655"
473+
},
473474
{
474475
key: "item_name",
475476
value: "abcd"
@@ -1088,8 +1089,8 @@ export class HelloWorldModel extends Observable {
10881089
type: firebase.LoginType.GOOGLE,
10891090
googleOptions: {
10901091
scopes: [
1091-
"https://www.googleapis.com/auth/contacts.readonly",
1092-
"https://www.googleapis.com/auth/user.birthday.read"
1092+
"https://www.googleapis.com/auth/contacts.readonly",
1093+
"https://www.googleapis.com/auth/user.birthday.read"
10931094
]
10941095
}
10951096
}).then(

demo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
},
1111
"dependencies": {
1212
"firebase-functions": "^2.0.5",
13-
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.3.tgz",
13+
"nativescript-plugin-firebase": "file:../publish/package/nativescript-plugin-firebase-9.0.4.tgz",
1414
"nativescript-theme-core": "^1.0.4",
1515
"nativescript-unit-test-runner": "0.7.0",
1616
"tns-core-modules": "6.0.1"

src/analytics/analytics-common.ts

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import { LogEventParameter } from "./analytics";
2+
3+
export function validateAnalyticsKey(key: string): string | undefined {
4+
if (key === undefined) {
5+
return "Argument 'key' is missing";
6+
}
7+
8+
if (key.length > 40) {
9+
return "Argument 'key' must be 40 characters or fewer";
10+
}
11+
12+
if (!key.match(/^[a-zA-Z][a-zA-Z_]+$/)) {
13+
return "Argument 'key' can only contain alphanumeric characters and underscores and must start with an alphanumeric character";
14+
}
15+
16+
if (key.startsWith("firebase_")) {
17+
return "Argument 'key' must not start with 'firebase_'";
18+
}
19+
20+
if (key.startsWith("google_")) {
21+
return "Argument 'key' must not start with 'google_'";
22+
}
23+
24+
if (key.startsWith("ga_")) {
25+
return "Argument 'key' must not start with 'ga_'";
26+
}
27+
28+
if ([
29+
"ad_activeview",
30+
"ad_click",
31+
"ad_exposure",
32+
"ad_impression",
33+
"ad_query",
34+
"adunit_exposure",
35+
"app_clear_data",
36+
"app_uninstall",
37+
"app_update",
38+
"error",
39+
"first_open",
40+
"first_visit",
41+
"in_app_purchase",
42+
"notification_dismiss",
43+
"notification_foreground",
44+
"notification_open",
45+
"notification_receive",
46+
"os_update",
47+
"screen_view",
48+
"session_start",
49+
"user_engagement"
50+
].indexOf(key) > -1) {
51+
return "Avoid using a reserved event name as the 'key' argument. Full list at: https://firebase.google.com/docs/reference/android/com/google/firebase/analytics/FirebaseAnalytics.Event";
52+
}
53+
54+
return undefined;
55+
}
56+
57+
export function validateAnalyticsParam(param: LogEventParameter): string | undefined {
58+
return validateAnalyticsParamKey(param.key) || validateAnalyticsParamValue(param.value);
59+
}
60+
61+
function validateAnalyticsParamKey(key: string): string | undefined {
62+
if (key === undefined) {
63+
return "Param 'key' is missing";
64+
}
65+
66+
if (key.length > 40) {
67+
return "Param 'key' must be 40 characters or fewer";
68+
}
69+
70+
if (!key.match(/^[a-zA-Z][a-zA-Z_]+$/)) {
71+
return "Param 'key' can only contain alphanumeric characters and underscores and must start with an alphanumeric character";
72+
}
73+
74+
return undefined;
75+
}
76+
77+
function validateAnalyticsParamValue(value: string): string | undefined {
78+
if (value === undefined) {
79+
return "Param 'value' is missing";
80+
}
81+
82+
if (value.length > 100) {
83+
return "Param 'value' must be 100 characters or fewer";
84+
}
85+
86+
if (value.startsWith("firebase_")) {
87+
return "Param 'value' must not start with 'firebase_'";
88+
}
89+
90+
if (value.startsWith("google_")) {
91+
return "Param 'value' must not start with 'google_'";
92+
}
93+
94+
if (value.startsWith("ga_")) {
95+
return "Param 'value' must not start with 'ga_'";
96+
}
97+
98+
return undefined;
99+
}

src/analytics/analytics.android.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
11
import * as appModule from "tns-core-modules/application";
2-
import {
3-
LogEventOptions,
4-
SetScreenNameOptions,
5-
SetUserPropertyOptions,
6-
LogComplexEventOptions,
7-
LogComplexEventParameter
8-
} from "./analytics";
2+
import { LogComplexEventOptions, LogComplexEventParameter, LogEventOptions, SetScreenNameOptions, SetUserPropertyOptions } from "./analytics";
3+
import { validateAnalyticsKey, validateAnalyticsParam } from "./analytics-common";
94

105
declare const com: any;
116

127
export function logEvent(options: LogEventOptions): Promise<void> {
138
return new Promise<void>((resolve, reject) => {
149
try {
15-
if (options.key === undefined) {
16-
reject("Argument 'key' is missing");
10+
const validationError = validateAnalyticsKey(options.key);
11+
if (validationError !== undefined) {
12+
reject(validationError);
1713
return;
1814
}
1915

2016
const bundle = new android.os.Bundle();
2117
if (options.parameters !== undefined) {
2218
for (const p in options.parameters) {
2319
const param = options.parameters[p];
20+
const validationParamError = validateAnalyticsParam(param);
21+
if (validationParamError !== undefined) {
22+
reject(validationParamError);
23+
return;
24+
}
25+
2426
if (param.value !== undefined) {
2527
bundle.putString(param.key, param.value);
2628
}

src/analytics/analytics.ios.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,25 @@
1-
import {
2-
LogEventOptions,
3-
SetScreenNameOptions,
4-
SetUserPropertyOptions,
5-
LogComplexEventOptions
6-
} from "./analytics";
1+
import { LogComplexEventOptions, LogEventOptions, SetScreenNameOptions, SetUserPropertyOptions } from "./analytics";
2+
import { validateAnalyticsKey, validateAnalyticsParam } from "./analytics-common";
73

84
export function logEvent(options: LogEventOptions): Promise<void> {
95
return new Promise<void>((resolve, reject) => {
106
try {
11-
if (options.key === undefined) {
12-
reject("Argument 'key' is missing");
7+
const validationError = validateAnalyticsKey(options.key);
8+
if (validationError !== undefined) {
9+
reject(validationError);
1310
return;
1411
}
1512

1613
const dic: any = NSMutableDictionary.new();
1714
if (options.parameters !== undefined) {
1815
for (let p in options.parameters) {
1916
const param = options.parameters[p];
17+
const validationParamError = validateAnalyticsParam(param);
18+
if (validationParamError !== undefined) {
19+
reject(validationParamError);
20+
return;
21+
}
22+
2023
if (param.value !== undefined) {
2124
dic.setObjectForKey(param.value, param.key);
2225
}

0 commit comments

Comments
 (0)