質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

解決済

1回答

1295閲覧

firestore rulesのテストでPERMISSION_DENIED

kobaryo04ysh

総合スコア29

Firebase

Firebaseは、Googleが提供するBasSサービスの一つ。リアルタイム通知可能、並びにアクセス制御ができるオブジェクトデータベース機能を備えます。さらに認証機能、アプリケーションのログ解析機能などの利用も可能です。

Cloud Firestore

Cloud Firestore は、自動スケーリングと高性能を実現し、アプリケーション開発を簡素化するように構築された NoSQLドキュメントデータベースです。

ユニットテスト

ユニットテストは、システムのテスト手法の一つで、個々のモジュールを対象としたテストの事を指します。対象のモジュールが要求や性能を満たしているか確認する為に実行します。

TypeScript

TypeScriptは、マイクロソフトによって開発された フリーでオープンソースのプログラミング言語です。 TypeScriptは、JavaScriptの構文の拡張であるので、既存の JavaScriptのコードにわずかな修正を加えれば動作します。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2020/12/13 05:09

Firebaseのrulesをテストしようとしていたのですが、エミュレータを起動して、npm testを実行すると、以下のエラーが発生しました。

FirebaseError: 7 PERMISSION_DENIED: false for 'create' @ L71

@ L71がline 71のことだとしたら、firestore.rulesファイルの71行目は
allow create: if isUserAuthenticated(userId) && isValidUserCreate(request.resource.data, userId);
です。(下記にコードを記載しています。)

参考しにた記事はこちらです。

そして、以下がテストコードになります。

rules.test.ts

1import * as firebase from "@firebase/rules-unit-testing"; 2import { TokenOptions } from "@firebase/rules-unit-testing/dist/src/api"; 3import { readFileSync } from "fs"; 4 5const projectId = "rule-test"; 6process.env.FIRESTORE_EMULATOR_HOST = "localhost:8080"; 7 8function getAuthFirestore(auth: TokenOptions) { 9 return firebase.initializeTestApp({ projectId, auth }).firestore(); 10} 11 12describe("firestore security test", () => { 13 beforeAll(async () => { 14 await firebase.loadFirestoreRules({ 15 projectId, 16 rules: readFileSync("firestore.rules", "utf8"), 17 }); 18 }); 19 20 afterEach(async () => { 21 await firebase.clearFirestoreData({ projectId }); 22 }); 23 24 afterAll(async () => { 25 await Promise.all(firebase.apps().map((app) => app.delete())); 26 }); 27 28 describe("ユーザー読み書きテスト", () => { 29 it("usersのデータは、ユーザ本人のみ書き込み可能", async () => { 30 const firestore = getAuthFirestore({ uid: "user" }); 31 const ref = firestore.collection("users").doc("user"); 32 await firebase.assertSucceeds(ref.set({ username: "サンプル" })); 33 34 const otherUserRef = firestore.collection("users").doc("userB"); 35 await firebase.assertFails(otherUserRef.set({ username: "サンプル" })); 36 }); 37 }); 38}); 39

また、以下はruleのコードになります。

firestore.rules

1rules_version = '2'; 2service cloud.firestore { 3 match /databases/{database}/documents { 4 5 function isAnyAuthenticated() { 6 return request.auth != null; 7 } 8 9 function isUserAuthenticated(userId) { 10 return isAnyAuthenticated() && userId == request.auth.uid; 11 } 12 13 function isValidUserCreate(user, targetUserId) { 14 return user.size() == 3 15 && 'email' in user && user.email is string 16 && 'username' in user && user.username is string 17 && 'uid' in user && user.uid is string && user.uid == targetUserId; 18 } 19 20 function isValidUserUpdate(user, targetUserId) { 21 return user.size() == 3 22 && 'email' in user && user.email is string 23 && 'username' in user && user.username is string 24 && 'uid' in user && user.uid is string && user.uid == targetUserId; 25 } 26 27 function isValidBookmarkAdd(bookmark) { 28 return bookmark.size() == 6 29 && 'authorName' in bookmark && bookmark.authorName is string && bookmark.authorName.size() > 0 30 && 'content' in bookmark && bookmark.content is string && bookmark.content.size() > 0 31 && 'createdAt' in bookmark && bookmark.createdAt is string 32 && 'id' in bookmark && bookmark.id is string 33 && 'saveId' in bookmark && bookmark.saveId is string 34 && 'title' in bookmark && bookmark.title is string && bookmark.title.size() > 0 35 } 36 37 function isValidBookmarkUpdate(bookmark) { 38 return bookmark.size() == 6 39 && 'authorName' in bookmark && bookmark.authorName is string && bookmark.authorName.size() > 0 40 && 'content' in bookmark && bookmark.content is string && bookmark.content.size() > 0 41 && 'createdAt' in bookmark && bookmark.createdAt is string 42 && bookmark.createdAt == resource.data.createdAt 43 && 'id' in bookmark && bookmark.id is string 44 && 'saveId' in bookmark && bookmark.saveId is string 45 && 'title' in bookmark && bookmark.title is string && bookmark.title.size() > 0 46 } 47 48 function isValidPostCreate(post) { 49 return post.size() == 6 50 && 'authorName' in post && post.authorName is string && post.authorName.size() > 0 51 && 'content' in post && post.content is string && post.content.size() > 0 52 && 'createdAt' in post && post.createdAt is timestamp 53 && 'category' in post && post.category is string 54 && 'uid' in post && post.uid is string 55 && 'title' in post && post.title is string && post.title.size() > 0 && post.title.size() <= 42 56 } 57 58 function isValidPostUpdate(post) { 59 return post.size() == 7 60 && 'authorName' in post && post.authorName is string && post.authorName.size() > 0 61 && 'content' in post && post.content is string && post.content.size() > 0 62 && 'createdAt' in post && post.createdAt is timestamp 63 && 'category' in post && post.category is string 64 && 'id' in post && post.id is string 65 && 'uid' in post && post.uid is string 66 && 'title' in post && post.title is string && post.title.size() > 0 && post.title.size() <= 42 67 } 68 69 match /users/{userId} { 70 allow get: if isUserAuthenticated(userId) || isAnyAuthenticated(); 71 allow create: if isUserAuthenticated(userId) && isValidUserCreate(request.resource.data, userId); 72 allow update: if isUserAuthenticated(userId) && isValidUserUpdate(request.resource.data, userId); 73 74 match /bookmarks/{bookmarkId} { 75 allow read: if isUserAuthenticated(userId); 76 allow create: if isUserAuthenticated(userId) && isValidBookmarkAdd(request.resource.data); 77 allow update: if isUserAuthenticated(userId) && isValidBookmarkUpdate(request.resource.data); 78 allow delete: if isUserAuthenticated(userId); 79 } 80 } 81 82 match /posts/{postId} { 83 allow read: if isUserAuthenticated(request.auth.uid); 84 allow create: if isUserAuthenticated(request.auth.uid) && isValidPostCreate(request.resource.data); 85 allow update: if isUserAuthenticated(request.auth.uid) && isValidPostUpdate(request.resource.data); 86 allow delete: if isUserAuthenticated(request.auth.uid); 87 } 88 } 89}

実現したいこと

・エラーを解消する
・testをpassすること

です。

auth関連のところで何かうまくいってなさそうなのはわかるのですが、調べてもいい感じの答えに辿り着けず、質問させていただきました。

環境

テストに使っているツールは、@firebase/rules-unit-testingです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

コードとルールを読む限り、

allow create: if isUserAuthenticated(userId) && isValidUserCreate(request.resource.data, userId);

の後半にあるisValidUserCreateに違反しているように見えます。

ルール

function isValidUserCreate(user, targetUserId) { return user.size() == 3 && 'email' in user && user.email is string && 'username' in user && user.username is string && 'uid' in user && user.uid is string && user.uid == targetUserId; }

コード

await firebase.assertSucceeds(ref.set({ username: "サンプル" }));

データの要素数が3であることをルール上で要求しているので、少なくともテストコード上でも要素数を揃えないとダメなのではないでしょうか。

投稿2020/12/14 02:21

attakei

総合スコア2740

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kobaryo04ysh

2020/12/14 04:06

できました!!ありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問