mirror of
https://github.com/pawelmalak/snippet-box.git
synced 2025-12-21 13:23:05 +01:00
Check snippet read permissions in controllers
This commit is contained in:
34
src/controllers/auth/getProfile.ts
Normal file
34
src/controllers/auth/getProfile.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import { Response, NextFunction } from 'express';
|
||||||
|
import { asyncWrapper } from '../../middleware';
|
||||||
|
import { UserInstance, UserModel } from '../../models';
|
||||||
|
import { UserInfoRequest } from '../../typescript/interfaces';
|
||||||
|
|
||||||
|
interface RequestBody {}
|
||||||
|
|
||||||
|
interface ResponseBody {
|
||||||
|
data: Omit<UserInstance, 'password'>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Get user profile by token
|
||||||
|
* @route /api/auth/me
|
||||||
|
* @request POST
|
||||||
|
* @access Public
|
||||||
|
*/
|
||||||
|
export const getProfile = asyncWrapper(
|
||||||
|
async (
|
||||||
|
req: UserInfoRequest<RequestBody>,
|
||||||
|
res: Response<ResponseBody>,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<void> => {
|
||||||
|
const user = (await UserModel.findOne({
|
||||||
|
where: { id: req.user.id },
|
||||||
|
attributes: { exclude: ['password'] },
|
||||||
|
raw: true
|
||||||
|
})) as UserInstance;
|
||||||
|
|
||||||
|
res.status(200).json({
|
||||||
|
data: user
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
@@ -2,6 +2,7 @@ import { Response, NextFunction } from 'express';
|
|||||||
import { QueryTypes } from 'sequelize';
|
import { QueryTypes } from 'sequelize';
|
||||||
import { sequelize } from '../../db';
|
import { sequelize } from '../../db';
|
||||||
import { asyncWrapper } from '../../middleware';
|
import { asyncWrapper } from '../../middleware';
|
||||||
|
import { UserInfoRequest } from '../../typescript/interfaces';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Count tags
|
* @description Count tags
|
||||||
@@ -10,13 +11,23 @@ import { asyncWrapper } from '../../middleware';
|
|||||||
* @access Private
|
* @access Private
|
||||||
*/
|
*/
|
||||||
export const countTags = asyncWrapper(
|
export const countTags = asyncWrapper(
|
||||||
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
async (
|
||||||
|
req: UserInfoRequest,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<void> => {
|
||||||
|
let where = !req.user.isAdmin
|
||||||
|
? `WHERE snippets.createdBy = ${req.user.id}`
|
||||||
|
: '';
|
||||||
|
|
||||||
const result = await sequelize.query(
|
const result = await sequelize.query(
|
||||||
`SELECT
|
`SELECT
|
||||||
COUNT(tags.name) as count,
|
COUNT(tags.name) as count,
|
||||||
tags.name
|
tags.name
|
||||||
FROM snippets_tags
|
FROM snippets_tags
|
||||||
INNER JOIN tags ON snippets_tags.tag_id = tags.id
|
INNER JOIN tags ON snippets_tags.tag_id = tags.id
|
||||||
|
INNER JOIN snippets ON snippets_tags.snippet_id = snippets.id
|
||||||
|
${where}
|
||||||
GROUP BY tags.name
|
GROUP BY tags.name
|
||||||
ORDER BY name ASC`,
|
ORDER BY name ASC`,
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import { Response, NextFunction } from 'express';
|
import { Response, NextFunction } from 'express';
|
||||||
import { asyncWrapper } from '../../middleware';
|
import { asyncWrapper } from '../../middleware';
|
||||||
import { SnippetModel, Snippet_TagModel } from '../../models';
|
import { SnippetModel, Snippet_TagModel } from '../../models';
|
||||||
import { Snippet, UserInfoRequest } from '../../typescript/interfaces';
|
import { UserInfoRequest } from '../../typescript/interfaces';
|
||||||
import { tagParser, createTags, ErrorResponse } from '../../utils';
|
import { ErrorResponse } from '../../utils';
|
||||||
|
|
||||||
interface Params {
|
interface Params {
|
||||||
id: number;
|
id: number;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { Request, Response, NextFunction } from 'express';
|
import { Response, NextFunction } from 'express';
|
||||||
import { asyncWrapper } from '../../middleware';
|
import { asyncWrapper } from '../../middleware';
|
||||||
import { SnippetModel, TagModel } from '../../models';
|
import { SnippetModel, TagModel } from '../../models';
|
||||||
|
import { UserInfoRequest } from '../../typescript/interfaces';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Get all snippets
|
* @description Get all snippets
|
||||||
@@ -8,7 +9,13 @@ import { SnippetModel, TagModel } from '../../models';
|
|||||||
* @request GET
|
* @request GET
|
||||||
*/
|
*/
|
||||||
export const getAllSnippets = asyncWrapper(
|
export const getAllSnippets = asyncWrapper(
|
||||||
async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
async (
|
||||||
|
req: UserInfoRequest,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
): Promise<void> => {
|
||||||
|
let where = req.user.isAdmin ? {} : { createdBy: req.user.id };
|
||||||
|
|
||||||
const snippets = await SnippetModel.findAll({
|
const snippets = await SnippetModel.findAll({
|
||||||
include: {
|
include: {
|
||||||
model: TagModel,
|
model: TagModel,
|
||||||
@@ -17,7 +24,8 @@ export const getAllSnippets = asyncWrapper(
|
|||||||
through: {
|
through: {
|
||||||
attributes: []
|
attributes: []
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
where
|
||||||
});
|
});
|
||||||
|
|
||||||
const populatedSnippets = snippets.map(snippet => {
|
const populatedSnippets = snippets.map(snippet => {
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
import { Request, Response, NextFunction } from 'express';
|
import { Response, NextFunction } from 'express';
|
||||||
import { asyncWrapper } from '../../middleware';
|
import { asyncWrapper } from '../../middleware';
|
||||||
import { SnippetModel, TagModel } from '../../models';
|
import { SnippetModel, TagModel } from '../../models';
|
||||||
import { Op } from 'sequelize';
|
import { Op } from 'sequelize';
|
||||||
|
import { UserInfoRequest } from '../../typescript/interfaces';
|
||||||
|
|
||||||
interface Body {
|
interface Body {
|
||||||
query: string;
|
query: string;
|
||||||
@@ -17,7 +18,7 @@ interface Body {
|
|||||||
*/
|
*/
|
||||||
export const searchSnippets = asyncWrapper(
|
export const searchSnippets = asyncWrapper(
|
||||||
async (
|
async (
|
||||||
req: Request<{}, {}, Body>,
|
req: UserInfoRequest<Body>,
|
||||||
res: Response,
|
res: Response,
|
||||||
next: NextFunction
|
next: NextFunction
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
@@ -49,6 +50,9 @@ export const searchSnippets = asyncWrapper(
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
language: languageFilter
|
language: languageFilter
|
||||||
|
},
|
||||||
|
{
|
||||||
|
createdBy: req.user.id
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
2
src/environment.d.ts
vendored
2
src/environment.d.ts
vendored
@@ -1,7 +1,7 @@
|
|||||||
declare global {
|
declare global {
|
||||||
namespace NodeJS {
|
namespace NodeJS {
|
||||||
interface ProcessEnv {
|
interface ProcessEnv {
|
||||||
PORT: number;
|
PORT: string;
|
||||||
NODE_ENV: string;
|
NODE_ENV: string;
|
||||||
JWT_SECRET: string;
|
JWT_SECRET: string;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,20 @@
|
|||||||
import { NextFunction, Request, Response } from 'express';
|
import { NextFunction, Response } from 'express';
|
||||||
import { asyncWrapper } from '.';
|
import { asyncWrapper } from '.';
|
||||||
import { ErrorResponse } from '../utils';
|
import { ErrorResponse } from '../utils';
|
||||||
import { verify } from 'jsonwebtoken';
|
import { verify } from 'jsonwebtoken';
|
||||||
import { Token, UserInfoRequest } from '../typescript/interfaces';
|
import { Token, UserInfoRequest } from '../typescript/interfaces';
|
||||||
import { UserModel } from '../models';
|
import { UserModel } from '../models';
|
||||||
|
|
||||||
|
interface Query {
|
||||||
|
token?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const authenticate = asyncWrapper(
|
export const authenticate = asyncWrapper(
|
||||||
async (req: UserInfoRequest, res: Response, next: NextFunction) => {
|
async (
|
||||||
|
req: UserInfoRequest<{}, {}, Query>,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction
|
||||||
|
) => {
|
||||||
let token: string | null = null;
|
let token: string | null = null;
|
||||||
|
|
||||||
// Check if token was provided
|
// Check if token was provided
|
||||||
@@ -14,6 +22,8 @@ export const authenticate = asyncWrapper(
|
|||||||
if (req.headers.authorization.startsWith('Bearer ')) {
|
if (req.headers.authorization.startsWith('Bearer ')) {
|
||||||
token = req.headers.authorization.split(' ')[1];
|
token = req.headers.authorization.split(' ')[1];
|
||||||
}
|
}
|
||||||
|
} else if (req.query.token) {
|
||||||
|
token = req.query.token;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (token) {
|
if (token) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ snippetRouter
|
|||||||
requireBody('title', 'language', 'code', 'tags'),
|
requireBody('title', 'language', 'code', 'tags'),
|
||||||
createSnippet
|
createSnippet
|
||||||
)
|
)
|
||||||
.get(getAllSnippets);
|
.get(authenticate, getAllSnippets);
|
||||||
|
|
||||||
snippetRouter
|
snippetRouter
|
||||||
.route('/:id')
|
.route('/:id')
|
||||||
@@ -29,6 +29,6 @@ snippetRouter
|
|||||||
.put(authenticate, updateSnippet)
|
.put(authenticate, updateSnippet)
|
||||||
.delete(authenticate, deleteSnippet);
|
.delete(authenticate, deleteSnippet);
|
||||||
|
|
||||||
snippetRouter.route('/statistics/count').get(countTags);
|
snippetRouter.route('/statistics/count').get(authenticate, countTags);
|
||||||
snippetRouter.route('/raw/:id').get(getRawCode);
|
snippetRouter.route('/raw/:id').get(authenticate, getRawCode);
|
||||||
snippetRouter.route('/search').post(searchSnippets);
|
snippetRouter.route('/search').post(authenticate, searchSnippets);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Request } from 'express';
|
import { Request } from 'express';
|
||||||
|
|
||||||
export interface UserInfoRequest<body = {}, params = {}>
|
export interface UserInfoRequest<body = {}, params = {}, query = {}>
|
||||||
extends Request<params, {}, body> {
|
extends Request<params, {}, body, query> {
|
||||||
user: {
|
user: {
|
||||||
id: number;
|
id: number;
|
||||||
email: string;
|
email: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user