Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
} else if (args) {
id = args.id || args.courseId;
}
if (!id) { return false; }
const userInfo = getUserInfo(context);
return (!userInfo.isInstructor) && context.db.exists.Course({
id: id,
students_some: {
id: userInfo.userId
}
});
});
const canAccessCourse = or(enrolledInCourse, ownsCourse);
const ownsQuiz = rule({
cache: 'strict',
fragment: 'fragment QuizId on Quiz { id }'
}) ((parent, args, context, info) => {
console.log('SHIELD: ownsQuiz?', args);
// ID to check could be parent object (from resolver), or `id` or similar argument from query
let id = null;
if (parent && parent.id) {
id = parent.id;
} else if (args) {
id = args.id || args.quizId;
}
if (!id) { return false; }
const userInfo = getUserInfo(context);
}
if (!id) { return false; }
const userInfo = getUserInfo(context);
return (!userInfo.isInstructor) && context.db.exists.Quiz({
id: id,
course: {
students_some: {
id: userInfo.userId
}
}
});
});
const canAccessQuiz = or(enrolledInQuiz, ownsQuiz);
const ownsQuestion = rule({
cache: 'strict',
fragment: 'fragment QuestionId on Question { id }'
}) ((parent, args, context, info) => {
console.log('SHIELD: ownsQuestion?');
// Question to check could be parent object (from resolver), or `id` or `questionId` argument from query
let id = null;
if (parent && parent.id) {
id = parent.id;
} else if (args) {
id = args.id || args.questionId;
}
if (!id) { return false; }
const userInfo = getUserInfo(context);
const userInfo = getUserInfo(context);
return (!userInfo.isInstructor && context.db.exists.Course({
quizzes_some: {
questions_some: {
id: id
}
},
students_some: {
id: userInfo.userId
}
}));
});
const canAccessQuestion = or(enrolledInQuestion, ownsQuestion);
// Unlike other entities in datamodel, a student “owns” a QuizAttempt
const ownsQuizAttempt = rule({
cache: 'strict',
fragment: 'fragment QuizAttemptId on QuizAttempt { id }'
}) ((parent, args, context, info) => {
console.log('SHIELD: ownsQuizAttempt?');
// ID to check could be parent object (from resolver), or `id` or similar argument from query
let id = null;
if (parent && parent.id) {
id = parent.id;
} else if (args) {
id = args.id || args.quizAttemptId;
}
if (!id) { return false; }
const email = getUserEmail(ctx)
return ctx.db.exists.Grocer({ email })
},
)
export const isCustomer = rule({ cache: 'contextual' })(
async (parent, args, ctx: Context, info) => {
// console.log('SHIELD: IsCustomer?')
const email = getUserEmail(ctx)
return ctx.db.exists.Customer({ email })
},
)
export const isAuthenticated = or(isCustomer, isGrocer)
async (parent, args, context: Ctx): Promise => {
const userId = await getUserId(context);
return !!userId;
}
),
isAdmin: rule({ cache: 'strict' })(
async (parent, args, context: Ctx): Promise => {
const userId = await getUserId(context);
const user: User = await context.prisma.user({ id: userId });
return user.role === 'ADMIN';
}
),
};
export const permissions = shield({
Query: {
// Global
'*': rules.isAdmin,
profile: rules.isUser,
},
Mutation: {
'*': rules.isAdmin,
login: allow,
signup: allow,
},
});
endpoint: config.PRISMA_ENDPOINT,
secret: config.PRISMA_SECRET,
debug: true,
});
// Set up our graphql server
const server = new GraphQLServer({
typeDefs: './src/schema.graphql',
resolvers,
resolverValidationOptions :{
requireResolversForResolveType: false
},
// Since the shield catches errors and masks as unauthorized,
// commenting this next line out is very helpful for debugging.
// Just make *certain* that it is uncommented before committing/pushing.
middlewares: [shield(Permissions)],
context: req => ({
...req,
// Allow this server's mutations and queries to access prisma server
db
}),
});
// Nginx proxy_passes to this server, and we want to trust its forwarded https headers, so that oauth signatures match
server.express.enable('trust proxy');
// Handle LTI launch requests
// create application/x-www-form-urlencoded parser
const urlencodedParser = bodyParser.urlencoded({ extended: false })
server.post('/lti', urlencodedParser, (req, res) => handleLaunch(config, db, req, res));
server.post('/lti/:action/:objectId', urlencodedParser, (req, res) => handleLaunch(config, db, req, res));
});
});
// To check undefined resolvers. Interesting we can use $Keys on Flow interface.
// Unfortunately, we can't use $ObjMap.
// TODO: Update codegen somehow to generate exact types for 100% coverage.
// The ideal DX: 1) add resolver 2) Flow warn about missing or wrong permission.
type Rules = {|
Mutation: { [$Keys]: Function },
Query: { [$Keys]: Function },
|};
const rules: Rules = {
Mutation: {
createWeb: isAuthenticated,
deleteWeb: and(isAuthenticated, isWebCreator(args => args.input.id)),
setTheme: isAuthenticated,
setPageTitle: and(isAuthenticated, isPageCreator(args => args.input.id)),
setWebName: and(isAuthenticated, isWebCreator(args => args.input.id)),
setPageElement: and(isAuthenticated, isPageCreator(args => args.input.id)),
deletePage: and(isAuthenticated, isPageCreator(args => args.input.id)),
},
Query: {
me: allow,
page: and(isAuthenticated, isPageCreator(args => args.id)),
web: and(isAuthenticated, isWebCreator(args => args.id)),
},
};
const permissions = shield(rules);
export default permissions;
return ctx.user.role === 'admin'
},
)
const isEditor = rule({ cache: 'contextual' })(
async (parent, args, ctx, info) => {
return ctx.user.role === 'editor'
},
)
// Permissions
const permissions = shield({
Query: {
frontPage: not(isAuthenticated),
fruits: and(isAuthenticated, or(isAdmin, isEditor)),
customers: and(isAuthenticated, isAdmin),
},
Mutation: {
addFruitToBasket: isAuthenticated,
},
Fruit: isAuthenticated,
Customer: isAdmin,
})
const server = GraphQLServer({
typeDefs,
resolvers,
middlewares: [permissions],
context: req => ({
...req,
user: getUser(req),
// Unfortunately, we can't use $ObjMap.
// TODO: Update codegen somehow to generate exact types for 100% coverage.
// The ideal DX: 1) add resolver 2) Flow warn about missing or wrong permission.
type Rules = {|
Mutation: { [$Keys]: Function },
Query: { [$Keys]: Function },
|};
const rules: Rules = {
Mutation: {
createWeb: isAuthenticated,
deleteWeb: and(isAuthenticated, isWebCreator(args => args.input.id)),
setTheme: isAuthenticated,
setPageTitle: and(isAuthenticated, isPageCreator(args => args.input.id)),
setWebName: and(isAuthenticated, isWebCreator(args => args.input.id)),
setPageElement: and(isAuthenticated, isPageCreator(args => args.input.id)),
deletePage: and(isAuthenticated, isPageCreator(args => args.input.id)),
},
Query: {
me: allow,
page: and(isAuthenticated, isPageCreator(args => args.id)),
web: and(isAuthenticated, isWebCreator(args => args.id)),
},
};
const permissions = shield(rules);
export default permissions;
},
)
const isEditor = rule({ cache: 'contextual' })(
async (parent, args, ctx, info) => {
return ctx.user.role === 'editor'
},
)
// Permissions
const permissions = shield({
Query: {
frontPage: not(isAuthenticated),
fruits: and(isAuthenticated, or(isAdmin, isEditor)),
customers: and(isAuthenticated, isAdmin),
},
Mutation: {
addFruitToBasket: isAuthenticated,
},
Fruit: isAuthenticated,
Customer: isAdmin,
})
const server = GraphQLServer({
typeDefs,
resolvers,
middlewares: [permissions],
context: req => ({
...req,
user: getUser(req),
}),