feat: added @auth directive

This commit is contained in:
Wyatt Johnson
2018-07-04 14:44:26 -06:00
parent e450fa05e0
commit 3e90877012
6 changed files with 67 additions and 18 deletions
-2
View File
@@ -19,7 +19,6 @@
"start:webpackDevServer": "node ./scripts/start.js",
"start": "node dist/index.js",
"test": "node scripts/test.js --env=jsdom",
"watch:types": "nodemon --config ./config/nodemon/types.json",
"watch": "NODE_ENV=development ts-node ./scripts/watcher/bin/watcher.ts ./config/watcher.ts"
},
"author": "",
@@ -112,7 +111,6 @@
"html-webpack-plugin": "^3.2.0",
"jest": "^23.2.0",
"loader-utils": "^1.1.0",
"nodemon": "^1.17.5",
"npm-run-all": "^4.1.3",
"postcss-flexbugs-fixes": "^3.3.1",
"postcss-font-magician": "^2.2.1",
+13
View File
@@ -0,0 +1,13 @@
import { User } from "talk-server/models/user";
export interface CommonContextOptions {
user?: User;
}
export default class CommonContext {
public user?: User;
constructor({ user }: CommonContextOptions) {
this.user = user;
}
}
@@ -1,12 +1,39 @@
import { DirectiveResolverFn } from "graphql-tools";
const auth: DirectiveResolverFn = (next, src, args, context) => {
return next().then(str => {
if (typeof str === "string") {
return str.toUpperCase();
import CommonContext from "talk-server/graph/common/context";
import { GQLUSER_ROLE } from "talk-server/graph/tenant/schema/__generated__/types";
export interface AuthDirectiveArgs {
roles?: GQLUSER_ROLE[];
userIDField?: string;
}
const auth: DirectiveResolverFn<
Record<string, string | undefined>,
CommonContext
> = (next, src, { roles, userIDField }: AuthDirectiveArgs, { user }) => {
// If there is a user on the request.
if (user) {
// If the role and user owner checks are disabled, then allow them based on
// their authenticated status.
if (!roles && !userIDField) {
return next();
}
return str;
});
// And the user has the expected role.
if (roles && roles.includes(user.role)) {
// Let the request continue.
return next();
}
// Or the item is owned by the specific user.
if (userIDField && src[userIDField] && src[userIDField] === user.id) {
return next();
}
}
// TODO: return better error.
throw new Error("not authorized");
};
export default auth;
+4 -1
View File
@@ -1,13 +1,16 @@
import { Db } from "mongodb";
import CommonContext from "talk-server/graph/common/context";
export interface ManagementContextOptions {
db: Db;
}
export default class ManagementContext {
export default class ManagementContext extends CommonContext {
public db: Db;
constructor({ db }: ManagementContextOptions) {
super({});
this.db = db;
}
}
+4 -3
View File
@@ -1,4 +1,5 @@
import { Db } from "mongodb";
import CommonContext from "talk-server/graph/common/context";
import { Tenant } from "talk-server/models/tenant";
import { User } from "talk-server/models/user";
import loaders from "./loaders";
@@ -10,16 +11,16 @@ export interface TenantContextOptions {
user?: User;
}
export default class TenantContext {
export default class TenantContext extends CommonContext {
public loaders: ReturnType<typeof loaders>;
public mutators: ReturnType<typeof mutators>;
public db: Db;
public tenant: Tenant;
public user?: User;
constructor({ user, tenant, db }: TenantContextOptions) {
super({ user });
this.tenant = tenant;
this.user = user;
this.loaders = loaders(this);
this.mutators = mutators(this);
this.db = db;
@@ -2,7 +2,14 @@
## Custom Directives
################################################################################
directive @auth(roles: [USER_ROLE!]!) on FIELD_DEFINITION
"""
auth is a directive that will enforce authorization rules on the schema
definition. It will restrict the viewer of the field based on roles or if the
`userIDField` is specified, it will see if the current users ID equals the field
specified. This allows users that own a specific resource (like a comment, or a
flag) see their own content, but restrict it to everyone else.
"""
directive @auth(roles: [USER_ROLE!], userIDField: String) on FIELD_DEFINITION
################################################################################
## Custom Scalar Types
@@ -195,7 +202,7 @@ type Settings {
autoCloseStream when true will auto close the stream when the `closeTimeout`
amount of seconds have been reached.
"""
autoCloseStream: Boolean!
autoCloseStream: Boolean! @auth(roles: [ADMIN])
"""
customCssUrl is the URL of the custom CSS used to display on the frontend.
@@ -254,12 +261,12 @@ type Settings {
"""
wordlist will return a given list of words.
"""
wordlist: WordlistSettings @auth(roles: [ADMIN])
wordlist: WordlistSettings @auth(roles: [ADMIN, MODERATOR])
"""
domains will return a given list of whitelisted domains.
"""
domains: [String!] @auth(roles: [ADMIN])
domains: [String!] @auth(roles: [ADMIN]) @auth(roles: [ADMIN])
"""
auth contains all the settings related to authentication and authorization.
@@ -294,7 +301,7 @@ type User {
"""
role is the current role of the User.
"""
role: USER_ROLE!
role: USER_ROLE! @auth(roles: [ADMIN, MODERATOR], userIDField: "id")
}
################################################################################
@@ -561,7 +568,7 @@ type Mutation {
"""
createComment will create a Comment as the current logged in User.
"""
createComment(input: CreateCommentInput!): CreateCommentPayload
createComment(input: CreateCommentInput!): CreateCommentPayload @auth
}
################################################################################