Skip to content

Commit df0c91b

Browse files
authored
Merge pull request #2 from StrontiumJS/master
merge original
2 parents ff631ce + 9329a20 commit df0c91b

File tree

10 files changed

+107
-29
lines changed

10 files changed

+107
-29
lines changed

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "strontium",
3-
"version": "2.5.1",
3+
"version": "2.6.6",
44
"description": "Strontium is a TypeScript toolkit for High Performance API servers built for Production not Projects.",
55
"main": "lib/src/index.js",
66
"types": "lib/src/index.d.ts",
@@ -68,7 +68,7 @@
6868
"base64url": "^3.0.0",
6969
"fastify": "^1.12.1",
7070
"inversify": "^5.0.1",
71-
"jwa": "^1.1.6",
71+
"jwa": "^1.2.0",
7272
"lodash": "^4.17.11",
7373
"mysql": "^2.16.0",
7474
"pg": "^7.5.0",

src/cryptography/drivers/node/AsymmetricJWTSigner.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,12 @@ export class AsymmetricJWTSigner extends JWTSigner {
5555
}
5656

5757
let claimBody = claimComponents[1]
58-
59-
let decodedSignature = new Buffer(decode(claimComponents[2]))
58+
let claimSignature = claimComponents[2]
6059

6160
// Delegate validation of the signature to the signer
6261
await this.signer.verify(
6362
new Buffer(`${claimHeader}.${claimBody}`),
64-
decodedSignature
63+
new Buffer(claimSignature)
6564
)
6665

6766
// If no error occurred then the token is valid. Parse the claim and return
Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,37 @@
11
import { AsymmetricSigner } from "../../abstract/AsymmetricSigner"
2+
import { InvalidSignatureError } from "../../../errors/InvalidSignatureError"
23

34
// Typescript Types not available for JWT - Proceed with caution
45
// @ts-ignore
56
import * as JWA from "jwa"
67

7-
const RS256 = JWA("RS256")
8-
98
export class RSASHA256Signer extends AsymmetricSigner {
9+
private signer = JWA(this.algorithm)
10+
11+
constructor(
12+
public publicKey: Buffer,
13+
public privateKey?: Buffer,
14+
private algorithm: "RS256" | "PS256" = "RS256"
15+
) {
16+
super(publicKey, privateKey)
17+
}
18+
1019
public async sign(plaintext: Buffer): Promise<Buffer> {
11-
return RS256.sign(plaintext, this.privateKey)
20+
return this.signer.sign(plaintext, this.privateKey)
1221
}
1322

1423
public async verify(plaintext: Buffer, signature: Buffer): Promise<Buffer> {
15-
return RS256.verify(plaintext, signature, this.publicKey)
24+
let isValid = await this.signer.verify(
25+
plaintext,
26+
signature.toString(),
27+
this.publicKey
28+
)
29+
30+
if (!isValid) {
31+
throw new InvalidSignatureError()
32+
}
33+
34+
// Spawn an empty buffer to fulfill the return type
35+
return Buffer.from([])
1636
}
1737
}

src/errors/InvalidSignatureError.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { StrontiumError } from "./StrontiumError"
2+
3+
/**
4+
* An InvalidSignatureError is thrown when a Cryptographic signature does not match.
5+
*/
6+
export class InvalidSignatureError extends StrontiumError {
7+
constructor() {
8+
super(`The signature provided was not valid.`)
9+
}
10+
}

src/http/drivers/FastifyServer.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ export class FastifyServer implements Process {
104104
// Attach the container to the server
105105
this.server.decorateRequest("container", container)
106106

107+
let plugins = this.getPlugins(container)
108+
for (let p of plugins) {
109+
this.server.register(p)
110+
}
111+
107112
let middleware = this.getMiddleware(container)
108113
for (let m of middleware) {
109114
this.server.use(m)
@@ -129,6 +134,12 @@ export class FastifyServer implements Process {
129134
return []
130135
}
131136

137+
protected getPlugins(
138+
container: Container
139+
): Array<Fastify.Plugin<any, any, any, any>> {
140+
return []
141+
}
142+
132143
protected getRequestMetadata = (
133144
request: Fastify.FastifyRequest<any, any, any, any, any>
134145
): { [key: string]: any } => ({})

src/query/drivers/sql/TableRepository.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { pgQueryPostProcessor } from "../pg/PGQueryPostProcessor"
22
import { Repository } from "../../abstract/Repository"
3-
import { MySQLStore, PGStore, SQLStore } from "../../../datastore"
3+
import {
4+
MySQLStore,
5+
MySQLTransaction,
6+
PGStore,
7+
SQLStore,
8+
} from "../../../datastore"
49
import { injectable } from "inversify"
510
import { isUndefined, omitBy } from "lodash"
611

@@ -32,6 +37,7 @@ export abstract class TableRepository<
3237

3338
if (store instanceof PGStore) {
3439
this.postProcessor = pgQueryPostProcessor
40+
this.tableName = `"${this.tableName}"`
3541
}
3642
}
3743

@@ -46,7 +52,10 @@ export abstract class TableRepository<
4652
// Filter the payload for any undefined keys
4753
let filteredPayload = (omitBy(payload, isUndefined) as unknown) as T
4854

49-
if (connection instanceof MySQLStore) {
55+
if (
56+
connection instanceof MySQLStore ||
57+
connection instanceof MySQLTransaction
58+
) {
5059
let insertQuery = `
5160
INSERT INTO
5261
??
@@ -64,15 +73,13 @@ export abstract class TableRepository<
6473
} else {
6574
let query = `
6675
INSERT INTO
67-
"${this.tableName}" (${Object.keys(filteredPayload).map(
68-
() => "??"
69-
)})
76+
?? (${Object.keys(filteredPayload).map(() => "??")})
7077
VALUES
7178
(${Object.keys(filteredPayload).map(() => "?")})
7279
RETURNING ??
7380
`
7481

75-
let parameters: Array<any> = []
82+
let parameters: Array<any> = [this.tableName]
7683

7784
Object.keys(filteredPayload).forEach((k: string) => {
7885
parameters.push(k)
@@ -108,13 +115,13 @@ export abstract class TableRepository<
108115
connection: SQLStore = this.store
109116
): Promise<Array<T>> {
110117
let [filterQuery, filterParameters] = compileSQLFilter(filter)
111-
let parameters = [...filterParameters]
118+
let parameters = [this.tableName, ...filterParameters]
112119

113120
let lookupQuery = `
114121
SELECT
115122
${this.queryFields.join(", ")}
116123
FROM
117-
"${this.tableName}"
124+
??
118125
${filterQuery !== "" ? "WHERE" : ""}
119126
${filterQuery}
120127
`
@@ -157,11 +164,11 @@ export abstract class TableRepository<
157164

158165
let lookupQuery = `
159166
UPDATE
160-
"${this.tableName}"
167+
??
161168
SET
162169
${Object.keys(filteredPayload).map(() => "?? = ?")}
163170
${filterQuery !== "" ? "WHERE" : ""}
164-
${filterQuery}
171+
${filterQuery}
165172
`
166173

167174
let payloadParameters: Array<any> = []
@@ -172,7 +179,7 @@ export abstract class TableRepository<
172179

173180
let [processedQuery, processedParameters] = this.postProcessor(
174181
lookupQuery,
175-
[...payloadParameters, ...filterParameters]
182+
[this.tableName, ...payloadParameters, ...filterParameters]
176183
)
177184
await connection.query(processedQuery, processedParameters)
178185
}
@@ -182,11 +189,11 @@ export abstract class TableRepository<
182189
connection: SQLStore = this.store
183190
): Promise<void> {
184191
let [filterQuery, filterParameters] = compileSQLFilter(filter)
185-
let parameters = [...filterParameters]
192+
let parameters = [this.tableName, ...filterParameters]
186193

187194
let lookupQuery = `
188195
DELETE FROM
189-
"${this.tableName}"
196+
??
190197
${filterQuery !== "" ? "WHERE" : ""}
191198
${filterQuery}
192199
`

src/validation/drivers/validators/isNumber.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
import { ValidationError } from "../../../errors/http/ValidationError"
22

33
export const isNumber = (input?: unknown): number => {
4-
if (typeof input === "number") {
4+
if (typeof input === "number" && !isNaN(input)) {
55
return input
66
}
77

8+
if (typeof input === "string") {
9+
let parsedNumber = Number(input)
10+
11+
if (!isNaN(parsedNumber)) {
12+
return parsedNumber
13+
}
14+
}
15+
816
throw new ValidationError(
917
"IS_NUMBER",
1018
"Value not a number",

tests/cryptography/drivers/node/AsymmetricJWTSigner.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,5 +99,22 @@ describe("AsymmetricJWTSigner", () => {
9999
admin: true,
100100
})
101101
})
102+
103+
it("Should throw if the JWT is invalid", async () => {
104+
try {
105+
await jwtSigner.verify(
106+
"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9" +
107+
"." +
108+
"eyJuYW1lIjoiSGVsbG8gV29ybGQiLCJhZG1pbiI6dHJ1ZX0" +
109+
"." +
110+
"abcdefg"
111+
)
112+
expect(true).to.equal(false)
113+
} catch (e) {
114+
expect(e.message).to.equal(
115+
"The signature provided was not valid."
116+
)
117+
}
118+
})
102119
})
103120
})

tests/validation/drivers/validators/isNumber.spec.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,16 @@ describe("isNumber", () => {
1010
expect(isNumber(123456789)).to.equal(123456789)
1111
})
1212

13+
it("should parse a string containing a number into a number", () => {
14+
expect(isNumber("1")).to.equal(1)
15+
expect(isNumber("0")).to.equal(0)
16+
expect(isNumber("0.001")).to.equal(0.001)
17+
expect(isNumber("-12423435.1")).to.equal(-12423435.1)
18+
expect(isNumber("+100")).to.equal(100)
19+
})
20+
1321
it("should return a validation error if input is not a number", () => {
1422
expectToThrowCustomClass(() => isNumber({}), ValidationError)
15-
expectToThrowCustomClass(() => isNumber("1"), ValidationError)
16-
expectToThrowCustomClass(() => isNumber("0"), ValidationError)
1723
expectToThrowCustomClass(() => isNumber("das"), ValidationError)
1824
expectToThrowCustomClass(() => isNumber("true"), ValidationError)
1925
expectToThrowCustomClass(() => isNumber("false"), ValidationError)

0 commit comments

Comments
 (0)