Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/emulator/storage/rules/runtime.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { expect } from "chai";
import { createAuthExpressionValue } from "./runtime";
import { RulesetOperationMethod } from "./types";

describe("Storage Rules Runtime", () => {
describe("createAuthExpressionValue", () => {
it("should return null if token is missing", () => {
const opts = {
file: {},
method: RulesetOperationMethod.GET,
path: "test/path",
projectId: "test-project",
};

const result = createAuthExpressionValue(opts);
expect(result).to.deep.equal({ null_value: null });
});

it("should return null if token is invalid", () => {
const opts = {
file: {},
token: "invalid-token",
method: RulesetOperationMethod.GET,
path: "test/path",
projectId: "test-project",
};

const result = createAuthExpressionValue(opts);
expect(result).to.deep.equal({ null_value: null });
});

it("should return auth value if token is valid (or at least decodable)", () => {
// Dummy token with payload: {"user_id": "test_user"}
const token = "eyJhbGciOiJub25lIn0.eyJ1c2VyX2lkIjoidGVzdF91c2VyIn0.";
const opts = {
file: {},
token: token,
method: RulesetOperationMethod.GET,
path: "test/path",
projectId: "test-project",
};

const result = createAuthExpressionValue(opts);
expect(result.map_value?.fields.uid).to.deep.equal({ string_value: "test_user" });
expect(result.map_value?.fields.token).to.exist;
});
Comment thread
kevmoo marked this conversation as resolved.
});
});
33 changes: 24 additions & 9 deletions src/emulator/storage/rules/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
issues: StorageRulesIssues;
}> {
if (opts.method === RulesetOperationMethod.LIST && this.rulesVersion < 2) {
const issues = new StorageRulesIssues();

Check warning on line 65 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

'StorageRulesIssues' was used before it was defined
issues.warnings.push(
"Permission denied. List operations are only allowed for rules_version='2'.",
);
Expand All @@ -75,7 +75,7 @@
return this.runtime.verifyWithRuleset(this.rulesetName, opts, runtimeVariableOverrides);
}

unload() {

Check warning on line 78 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
throw new Error("NOT_IMPLEMENTED");
}
}
Expand All @@ -86,11 +86,11 @@
public warnings: string[] = [],
) {}

static fromResponse(resp: RuntimeActionResponse) {

Check warning on line 89 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
return new StorageRulesIssues(resp.errors || [], resp.warnings || []);
}

get all() {

Check warning on line 93 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
return [...this.errors, ...this.warnings];
}

Expand All @@ -109,18 +109,18 @@
private _requestCount = 0;
private _requests: {
[s: number]: {
handler: (rap: any) => void;

Check warning on line 112 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
request: RuntimeActionRequest;
};
} = {};
private _childprocess?: ChildProcess;
private _alive = false;

get alive() {

Check warning on line 119 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
return this._alive;
}

async start(autoDownload = true) {

Check warning on line 123 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing return type on function
if (this.alive) {
return;
}
Expand Down Expand Up @@ -167,7 +167,7 @@
});

// This catches error when spawning the java process
this._childprocess.on("error", (err: any) => {

Check warning on line 170 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
void handleEmulatorProcessError(Emulators.STORAGE, err);
});

Expand All @@ -193,7 +193,7 @@
let rap;
try {
rap = JSON.parse(serializedRuntimeActionResponse) as RuntimeActionResponse;
} catch (err: any) {

Check warning on line 196 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
EmulatorLogger.forEmulator(Emulators.STORAGE).log(
"INFO",
serializedRuntimeActionResponse,
Expand All @@ -210,7 +210,7 @@
const request = this._requests[id];

if (rap.status !== "ok" && !("action" in rap)) {
console.warn(`[RULES] ${rap.status}: ${rap.message}`);

Check warning on line 213 in src/emulator/storage/rules/runtime.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "string | undefined" of template literal expression
rap.errors.forEach(console.warn.bind(console));
return;
}
Expand Down Expand Up @@ -389,6 +389,10 @@
}
}

/**
* Converts a JS object to an ExpressionValue for the rules runtime.
* @internal
*/
function toExpressionValue(obj: any): ExpressionValue {
if (typeof obj === "string") {
return { string_value: obj };
Expand Down Expand Up @@ -470,21 +474,32 @@
}
}

function createAuthExpressionValue(opts: RulesetVerificationOpts): ExpressionValue {
/**
* Creates an ExpressionValue for the auth object in rules.
* @internal
*/
export function createAuthExpressionValue(opts: RulesetVerificationOpts): ExpressionValue {
Comment thread
kevmoo marked this conversation as resolved.
if (!opts.token) {
return toExpressionValue(null);
} else {
const tokenPayload = jwt.decode(opts.token, { json: true }) as any;

const jsonValue = {
uid: tokenPayload.user_id,
token: tokenPayload,
};
}
const tokenPayload = jwt.decode(opts.token, { json: true });

return toExpressionValue(jsonValue);
if (typeof tokenPayload !== "object" || !tokenPayload) {
return toExpressionValue(null);
}

const jsonValue = {
uid: "user_id" in tokenPayload ? tokenPayload.user_id : undefined,
token: tokenPayload,
};

return toExpressionValue(jsonValue);
}

/**
* Creates an ExpressionValue for the request object in rules.
* @internal
*/
function createRequestExpressionValue(opts: RulesetVerificationOpts): ExpressionValue {
const fields: { [s: string]: ExpressionValue } = {
path: {
Expand Down
Loading