Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding support to latest version #25

Merged
merged 1 commit into from
Mar 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ deno_mongo
### Libraries Used

- [x] [Oak](https://deno.land/x/oak) - A middleware framework for Deno's net
server
server
- [x] [deno_mongo](https://deno.land/x/mongo) - MongoDB driver for Deno
- [x] [cors](https://deno.land/x/cors) - Deno.js CORS middleware
- [x] [djwt](https://deno.land/x/djwt) - To make JSON Web Tokens in deno. Based
on JWT and JWS specifications.
on JWT and JWS specifications.
- [x] [yup](https://github.com/jquense/yup) - Schema builder for value parsing
and validation
- [x] [god_crypto](https://deno.land/x/god_crypto) - Encrypts passwords in AES
to save in database collection.
and validation
- [x] [bcrypt](https://deno.land/x/bcrypt) - Encrypts passwords to save in
database collection.

## Getting Started

Expand All @@ -40,19 +40,19 @@ deno_mongo
**Using Deno:**

```
deno upgrade --version 1.11.5
deno upgrade --version 1.20.3
```

**With Shell:**

```
curl -fsSL https://deno.land/x/install/install.sh | sh -s v1.11.5
curl -fsSL https://deno.land/x/install/install.sh | sh -s v1.20.3
```

**With PowerShell:**

```
$v="1.11.5"; iwr https://deno.land/x/install/install.ps1 -useb | iex
$v="1.20.3"; iwr https://deno.land/x/install/install.ps1 -useb | iex
```

Clone this repository to your local machine
Expand Down
3 changes: 2 additions & 1 deletion app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import log from "./middlewares/logger.middleware.ts";
import configs from "./config/config.ts";
import router from "./routers/index.ts";

const { url, port, clientUrl } = configs;
const { env, url, port, clientUrl } = configs;

const app: Application = new Application();

Expand All @@ -22,6 +22,7 @@ app.use(errorHandler);
router.init(app);

app.addEventListener("listen", () => {
log.info(`Current Environment: ${env}`);
log.info(`Server listening at ${url}`);
});

Expand Down
10 changes: 2 additions & 8 deletions config/config.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { dotEnv } from "../deps.ts";

const env: string = Deno.env.toObject().ENV || "test";
const envPath: string = `.env/.env.${env}`.toString();
const env: string = Deno.env.get("ENV") || "development";
const envPath: string = `environments/.env.${env}`.toString();
const envConfig = dotEnv({
path: envPath,
});
Expand All @@ -22,11 +22,8 @@ if (env === "development" || env === "test") {
const config: ({
env: string;
appName: string;
key: string;
jwtSecret: string;
jwtAccessExpiration: number;
jwtRefreshExpiration: number;
salt: string;
ip: string;
host: string;
port: number;
Expand All @@ -42,11 +39,8 @@ const config: ({
}) = {
env,
appName: envConfig.APP_NAME,
key: envConfig.KEY,
jwtSecret: envConfig.JWT_SECRET,
jwtAccessExpiration: Number(envConfig.JWT_ACCESS_TOKEN_EXP),
jwtRefreshExpiration: Number(envConfig.JWT_REFRESH_TOKEN_EXP),
salt: envConfig.SALT,
ip: envConfig.IP,
host: envConfig.HOST,
port: Number(envConfig.PORT),
Expand Down
4 changes: 2 additions & 2 deletions controllers/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class AuthController {
* @returns Promise<void>
*/
public static async login(
{ request, response }: RouterContext,
{ request, response }: RouterContext<string>,
): Promise<void> {
const body = request.body();
const { email, password } = await body.value;
Expand All @@ -25,7 +25,7 @@ class AuthController {
* @returns Promise<void>
*/
public static async refreshTokens(
{ request, response }: RouterContext,
{ request, response }: RouterContext<string>,
): Promise<void> {
const body = request.body();
const { refreshToken } = await body.value;
Expand Down
16 changes: 10 additions & 6 deletions controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class UserController {
* @returns Promise<void>
*/
public static async create(
{ request, response }: RouterContext,
{ request, response }: RouterContext<string>,
): Promise<void> {
const body = request.body();
const {
Expand All @@ -36,7 +36,9 @@ class UserController {
* @param response
* @returns Promise<void>
*/
public static async fetch({ response }: RouterContext): Promise<void> {
public static async fetch(
{ response }: RouterContext<string>,
): Promise<void> {
log.debug("Getting users list");
response.body = await UserService.getUsers();
}
Expand All @@ -47,7 +49,7 @@ class UserController {
* @param response
* @returns Promise<void>
*/
public static me({ state, response }: RouterContext): void {
public static me({ state, response }: RouterContext<string>): void {
log.debug("Getting me data");
response.body = state;
}
Expand All @@ -58,7 +60,9 @@ class UserController {
* @param response
* @returns Promise<void>
*/
public static async show({ params, response }: RouterContext): Promise<void> {
public static async show(
{ params, response }: RouterContext<string>,
): Promise<void> {
const { id } = params;
log.debug("Getting user");
response.body = await UserService.getUser(id as string);
Expand All @@ -72,7 +76,7 @@ class UserController {
* @returns Promise<void>
*/
public static async update(
{ params, request, response }: RouterContext,
{ params, request, response }: RouterContext<string>,
): Promise<void> {
const { id } = params;
const body = request.body();
Expand All @@ -92,7 +96,7 @@ class UserController {
* @returns Promise<void>
*/
public static async remove(
{ params, response }: RouterContext,
{ params, response }: RouterContext<string>,
): Promise<void> {
const { id } = params;
log.debug("Removing user");
Expand Down
32 changes: 10 additions & 22 deletions denon.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,37 @@
"net",
"env",
"read",
"write",
"plugin"
"write"
],
"scripts": {
"start": {
"cmd": "deno run app.ts",
"unstable": true,
"unstable": false,
"desc": "run server",
"env": {
"ENV": "development"
},
"watch": true,
"tsconfig": "tsconfig.json",
"lock": "lock.json"
"tsconfig": "tsconfig.json"
},
"test": {
"cmd": "deno test",
"desc": "Test the server.",
"unstable": true,
"unstable": false,
"env": {
"ENV": "test"
},
"watch": false,
"tsconfig": "tsconfig.json",
"lock": "lock.json"
"tsconfig": "tsconfig.json"
},
"prod": {
"cmd": "deno run app.bundle.js",
"desc": "Run the server.",
"unstable": true,
"unstable": false,
"env": {
"ENV": "production"
},
"watch": false,
"lock": "lock.json"
"watch": false
},
"fmt": {
"cmd": "deno fmt",
Expand All @@ -61,22 +57,14 @@
},
"watcher": {
"interval": 350,
"exts": [
"js",
"jsx",
"ts",
"tsx",
"json"
],
"match": [
"*.*"
],
"exts": ["js", "jsx", "ts", "tsx", "json"],
"match": ["**/*.*"],
"skip": [
"*/.git/*",
"*/.idea/*",
"*/.vscode/*",
"*/.env/*"
],
"legacy": true
"legacy": false
}
}
7 changes: 3 additions & 4 deletions deps.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as yup from "https://cdn.skypack.dev/yup";

export { AES, encode } from "https://deno.land/x/god_crypto/mod.ts";
export { compare, genSalt, hash } from "https://deno.land/x/bcrypt/mod.ts";
export {
Application,
Context,
Expand All @@ -13,10 +13,9 @@ export {
export type { RouterContext, State } from "https://deno.land/x/oak/mod.ts";
export { config as dotEnv } from "https://deno.land/x/dotenv/mod.ts";
export { getLogger, handlers, setup } from "https://deno.land/std/log/mod.ts";
export { MongoClient } from "https://deno.land/x/mongo/mod.ts";
export { Bson, MongoClient } from "https://deno.land/x/mongo/mod.ts";
export type { Document } from "https://deno.land/x/mongo/mod.ts";
export { ObjectId } from "https://deno.land/x/mongo/bson/mod.ts";
export { oakCors } from "https://deno.land/x/cors/mod.ts";
export type { Header, Payload } from "https://deno.land/x/djwt/mod.ts";
export { create, verify } from "https://deno.land/x/djwt/mod.ts";
export { create, decode, verify } from "https://deno.land/x/djwt/mod.ts";
export { yup };
3 changes: 0 additions & 3 deletions .env/.env.example → environments/.env.example
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
APP_NAME=Deno REST - Boilerplate for deno RESTful apis
JWT_SECRET=SOME_AWSOME_JWT_SECRET
JWT_ACCESS_TOKEN_EXP=3600
JWT_REFRESH_TOKEN_EXP=1800
KEY=YOUR_AES_KEY_FOR_PASSWORD_ENCRYPTION
SALT=random_16byte_iv
SEED=false
IP=0.0.0.0
HOST=localhost
Expand Down
38 changes: 10 additions & 28 deletions helpers/hash.helper.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,27 @@
import configs from "../config/config.ts";
import { AES, encode } from "../deps.ts";
import { compare, genSalt, hash } from "../deps.ts";

class HashHelper {
private static key: string = configs.key;
private static salt: string = configs.salt;

private static aes(): AES {
return new AES(this.key, { mode: "cbc", iv: this.salt });
}

/**
* Encrypts plain string and returns cipher in hex
* Encrypts plain string and returns password hash
* @param str
* @returns Promise<string> Returns encrypted cipher in hex format
* @returns Promise<string> Returns encrypted password hash
*/
public static async encrypt(str: string): Promise<string> {
const cipher = await this.aes().encrypt(str);
return cipher.hex();
}

/**
* Decrypts AES hex and returns plain string
* @param str
* @returns Promise<string> Returns decrypted cipher in plain string format
*/
public static async decrypt(str: string): Promise<string> {
const plain = await this.aes().decrypt(encode.hex(str));
return plain.toString();
const salt = await genSalt(8);
return hash(str, salt);
}

/**
* Compares encrypted and provided string
* Compares hash
* @param plain
* @param encrypted
* @returns Promise<boolean> Returns Boolean if provided string and encrypted string are equal
* @param _hash
* @returns Promise<boolean> Returns Boolean if provided string and hash are equal
*/
public static async compare(
plain: string,
encrypted: string,
_hash: string,
): Promise<boolean> {
return await this.encrypt(plain) === encrypted;
return await compare(plain, _hash);
}
}

Expand Down
36 changes: 20 additions & 16 deletions helpers/jwt.helper.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,37 @@
import configs from "../config/config.ts";
import { create, Header, Payload, Status, verify } from "../deps.ts";
import { create, Status, verify } from "../deps.ts";
import type { Header, Payload } from "../deps.ts";
import { throwError } from "../middlewares/errorHandler.middleware.ts";

const { jwtSecret } = configs;

const header: Header = {
alg: "HS512",
typ: "JWT",
};
const key = await crypto.subtle.generateKey(
{ name: "HMAC", hash: "SHA-512" },
true,
["sign", "verify"],
);

class JwtHelper {
/**
* Generate JWT token
* @param expires
* @param exp Expiry
* @param id
* @returns Promise<string> Returns JWT
* @returns String Returns JWT
*/
public static getToken(
expires: number,
exp: number,
id?: string,
): Promise<string> {
const now = Date.now(); // in millis
const header: Header = {
alg: "HS512",
typ: "JWT",
};
const payload: Payload = {
iss: "djwt",
iat: Date.now(),
iss: "deno_rest",
iat: now,
id,
exp: Date.now() / 1000 + expires, // in seconds
exp,
};

return create(header, payload, jwtSecret);
return create(header, payload, key);
}

/**
Expand All @@ -37,7 +41,7 @@ class JwtHelper {
*/
public static async getJwtPayload(token: string): Promise<Payload | Error> {
try {
return await verify(token, jwtSecret, "HS512");
return await verify(token, key);
} catch (_e) {
return throwError({
status: Status.Unauthorized,
Expand Down
Loading