Skip to content

Commit

Permalink
Merge pull request #25 from vicky-gonsalves/supoort-latest-version
Browse files Browse the repository at this point in the history
Adding support to latest version
  • Loading branch information
vicky-gonsalves committed Mar 30, 2022
2 parents ceb8628 + 26e9e64 commit 51eded6
Show file tree
Hide file tree
Showing 17 changed files with 293 additions and 376 deletions.
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

0 comments on commit 51eded6

Please sign in to comment.