Merge branch 'develop' of https://github.com/AntlerVC/firetable into develop

This commit is contained in:
Sidney Alcantara
2020-09-05 13:25:40 +10:00
13 changed files with 1105 additions and 21 deletions

View File

@@ -44,8 +44,8 @@ supported. More coming soon, for comprehensive list see ROADMAP.md.
- Upgrade project to the Blaze Plan
- Enable the Google sign-in method in **Authentication / Sign-in method**
- **⚠️ IMPORTANT:** If you try to sign in and see “This account does not
exist”, run
- **⚠️ IMPORTANT:** If you try to sign in and see “This account does not have
any roles”, run
[the following script](https://github.com/AntlerVC/firetable/blob/develop/RULES.md#custom-claims)
on your Firebase Authentication user.
@@ -126,9 +126,9 @@ yarn start
[Please create issues here.](https://github.com/antlervc/firetable/issues)
Make sure to provide console log outputs and screenshots!
### Known Issue: “This account does not exist
### Known Issue: “This account does not have any roles
If you try to sign in and see “This account does not exist”, run
If you try to sign in and see “This account does not have any roles”, run
[the following script](https://github.com/AntlerVC/firetable/blob/develop/RULES.md#custom-claims)
on your Firebase Authentication user.

View File

@@ -51,8 +51,11 @@ The firetable roles are stored in the users firebase auth token custom claims
### setting roles
this a basic script for setting your user roles. you can run this locally using
the adm sdk or implement it in your cloud functions
You can use the CLI tool to set your roles
[here](https://github.com/AntlerVC/firetable/blob/master/cli/README.md#Setting-user-Roles)
It relays on this basic script. you can run this locally using the adm sdk or
implement it in your cloud functions
```js
import * as admin from "firebase-admin";

View File

@@ -6,6 +6,7 @@ Make sure you have the following installed:
- [Git](https://git-scm.com/downloads)
- [Node](https://nodejs.org/en/download/)
- [Yarn](https://classic.yarnpkg.com/en/docs/install/)
- [Firebase CLI](https://firebase.google.com/docs/cli)
Also make sure you are logged in to your Firebase account in the Firebase CLI.
@@ -47,3 +48,25 @@ First, make sure that you have created a site in your Firebase project.
```
firetable deploy
```
## Firebase Rules & Firetable roles
Read more about firebase rules for firetable
[HERE](https://github.com/AntlerVC/firetable/blob/master/RULES.md)
### Setting user Roles
Download the admin key for your project then add it to the directory without
renaming it. You can find your service account here:
https://console.firebase.google.com/u/0/project/_/settings/serviceaccounts/adminsdk
```
firetable auth:setRoles <email> <roles>
```
email: needs to be associated with an existing firebase account on the example
roles: can be one role `ADMIN` or a comma separated array `ADMIN,OPS,DEV`
```
firetable auth:setRoles shams@antler.co OPS,INTERNAL
```

View File

@@ -16,6 +16,7 @@
"commander": "^6.0.0",
"configstore": "^5.0.1",
"figlet": "^1.5.0",
"firebase-admin": "^9.1.1",
"inquirer": "^7.3.3",
"lodash": "^4.17.19",
"open": "^7.1.0"

View File

@@ -6,11 +6,11 @@ const terminal = require("./lib/terminal");
const inquirer = require("./lib/inquirer");
const Configstore = require("configstore");
const config = new Configstore("firetable");
const { directoryExists } = require("./lib/files");
const { directoryExists, findFile } = require("./lib/files");
const process = require("process");
const { Command } = require("commander");
const { version } = require("../package.json");
const { setUserRoles } = require("./lib/firebaseAdmin");
const program = new Command();
program.version(version);
@@ -34,7 +34,6 @@ const systemHealthCheck = async () => {
Object.entries(versions).forEach(([app, version]) =>
console.log(`${app.padEnd(8)} ${chalk.green(version)}`)
);
console.log();
};
// checks the current directory of the cli app
@@ -207,4 +206,41 @@ program
}
});
program
.command("auth:setRoles <email> <roles>")
.description(
"Adds roles to the custom claims of a specified firebase account."
)
.action(async (email, roles) => {
try {
// check directory for admin sdk json
const adminSDKFilePath = await findFile(/.*-firebase-adminsdk.*json/);
// let directory = await directoryCheck();
// if (!directory) return;
// await deploy2firebase(directory);
const result = await setUserRoles(adminSDKFilePath)(
email,
roles.split(",")
);
if (result.success) {
console.log(result.message);
return;
} else if (result.code === "auth/user-not-found") {
console.log(
chalk.bold(chalk.red("FAILED: ")),
`could not find an account corresponding with`,
chalk.bold(email)
);
return;
} else {
console.log(chalk.bold(chalk.red(result.message)));
return;
}
} catch (error) {
console.log("\u{1F6D1}" + chalk.bold(chalk.red(" FAILED")));
console.log(error);
}
});
program.parse(process.argv);

View File

@@ -9,4 +9,19 @@ module.exports = {
directoryExists: (filePath) => {
return fs.existsSync(filePath);
},
findFile: (fileRegex) =>
new Promise((resolve, reject) =>
fs.readdir("./", (err, files) => {
const file = files
.map((file) => file.match(fileRegex))
.filter((_file) => _file)[0];
if (file) {
resolve(file[0]);
} else {
reject(
"Can not find the firebase service account key json file, download the admin key for your project then add it to this directory without renaming it.\nYou can find your service account here: https://console.firebase.google.com/u/0/project/_/settings/serviceaccounts/adminsdk"
);
}
})
),
};

View File

@@ -0,0 +1,36 @@
const admin = require("firebase-admin");
const fs = require("fs");
const initializeApp = (serviceAccountFile) => {
console.log(serviceAccountFile);
var serviceAccount = fs.readFileSync(`./${serviceAccountFile}`, {
encoding: "utf8",
});
const serviceAccountJSON = JSON.parse(serviceAccount);
admin.initializeApp({
credential: admin.credential.cert(serviceAccountJSON),
databaseURL: `https://${serviceAccountJSON.project_id}.firebaseio.com`,
});
const auth = admin.auth();
return { auth };
};
module.exports.setUserRoles = (serviceAccountFile) => async (email, roles) => {
try {
const { auth } = initializeApp(serviceAccountFile);
// Initialize Auth
// sets the custom claims on an account to the claims object provided
const user = await auth.getUserByEmail(email);
await auth.setCustomUserClaims(user.uid, { ...user.customClaims, roles });
return {
success: true,
message: `${email} now has the following roles ✨${roles.join(
" & "
)}`,
};
} catch (error) {
return {
success: false,
code: "auth/user-not-found",
message: error.message,
};
}
};

File diff suppressed because it is too large Load Diff

View File

@@ -40,7 +40,7 @@ const useSettings = () => {
//create the firetable collection doc with empty columns
db.collection("_FIRETABLE_/settings/schema")
.doc(data.collection)
.set({ ...data, columns: [] }, { merge: true });
.set({ ...data }, { merge: true });
};
const updateTable = (data: {

View File

@@ -24,6 +24,7 @@ export const SnackProvider: React.FC<ISnackProviderProps> = ({ children }) => {
setMessage("");
setDuration(0);
setSeverity(undefined);
setAction(<div />);
};
const open = (props: {
message: string;

View File

@@ -8,6 +8,8 @@ import AuthCard from "./AuthCard";
import { handleGoogleAuth } from "./utils";
import GoogleLogo from "assets/google-icon.svg";
import { useSnackContext } from "contexts/snackContext";
import { Link } from "react-router-dom";
import { auth } from "../../firebase";
export default function GoogleAuthView() {
const [loading, setLoading] = useState(false);
const snack = useSnackContext();
@@ -27,7 +29,45 @@ export default function GoogleAuthView() {
},
(error: Error) => {
setLoading(false);
snack.open({ message: error.message });
console.log(error);
if (
error.message ===
"The identity provider configuration is disabled."
) {
snack.open({
severity: "warning",
message:
"You need to enable Google authentication in your firebase project",
action: (
<Button
component="a"
href={`https://console.firebase.google.com/u/0/project/${auth.app.options["projectId"]}/authentication/providers`}
target="_blank"
>
Go to settings
</Button>
),
});
} else if (
error.message === "This account does not have any roles"
) {
snack.open({
severity: "warning",
message:
"You need to enable Google authentication in your firebase project",
action: (
<Button
component="a"
href={`https://github.com/AntlerVC/firetable/blob/master/RULES.md`}
target="_blank"
>
Instructions
</Button>
),
});
} else {
snack.open({ message: error.message });
}
},
parsedQuery.email as string
);

View File

@@ -14,7 +14,7 @@ export const handleGoogleAuth = async (
if (result.claims.roles && result.claims.roles.length !== 0) {
success(authUser, result.claims.roles);
} else {
throw Error("This account does not exist");
throw Error("This account does not have any roles");
}
} catch (error) {
if (auth.currentUser) {

View File

@@ -1,6 +1,7 @@
import React, { useEffect } from "react";
import queryString from "query-string";
import { useFiretableContext } from "contexts/firetableContext";
import { useAppContext } from "contexts/appContext";
import { Hidden } from "@material-ui/core";
@@ -12,11 +13,12 @@ import { FireTableFilter } from "hooks/useFiretable";
import useRouter from "hooks/useRouter";
import ImportWizard from "components/Wizards/ImportWizard";
import { DocActions } from "hooks/useDoc";
export default function TableView() {
const router = useRouter();
const tableCollection = decodeURIComponent(router.match.params.id);
const { tableState, tableActions, sideDrawerRef } = useFiretableContext();
const { userDoc } = useAppContext();
let filters: FireTableFilter[] = [];
const parsed = queryString.parse(router.location.search);
if (typeof parsed.filters === "string") {
@@ -32,7 +34,15 @@ export default function TableView() {
tableState &&
tableState.tablePath !== tableCollection
) {
tableActions.table.set(tableCollection, filters);
if (filters && filters.length !== 0) {
tableActions.table.set(tableCollection, filters);
userDoc.dispatch({
action: DocActions.update,
data: {
tables: { [`${tableState?.tablePath}`]: { filters } },
},
});
}
if (sideDrawerRef?.current) sideDrawerRef.current.setCell!(null);
}
}, [tableCollection]);