mirror of
https://github.com/zhigang1992/hasura-backend-plus.git
synced 2026-01-12 17:22:59 +08:00
🔥 Cleaning up
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
examples
|
||||
node_modules
|
||||
npm-debug.log
|
||||
npm-debug.log
|
||||
|
||||
@@ -8,4 +8,4 @@ indent_size = 2
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -3,7 +3,7 @@ dist
|
||||
*.log
|
||||
hasura
|
||||
config.yaml
|
||||
private.pem
|
||||
node_modules
|
||||
yarn-error.log
|
||||
package-lock.json
|
||||
private.pem
|
||||
|
||||
2
LICENSE
2
LICENSE
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
||||
@@ -121,4 +121,4 @@ insert into public.roles (role)
|
||||
values ('anonymous');
|
||||
|
||||
insert into auth.auth_providers (provider)
|
||||
values ('github'), ('facebook'), ('twitter'), ('google');
|
||||
values ('github'), ('facebook'), ('twitter'), ('google');
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"helmet": "3.21.3",
|
||||
"hibp": "8.0.0",
|
||||
"jose": "1.25.0",
|
||||
"nodemailer": "6.4.5",
|
||||
"otplib": "12.0.1",
|
||||
"qrcode": "1.4.4",
|
||||
"tsconfig-paths": "3.9.0",
|
||||
@@ -49,6 +50,7 @@
|
||||
"@types/jest": "25.1.4",
|
||||
"@types/jsonwebtoken": "8.3.8",
|
||||
"@types/node": "13.9.1",
|
||||
"@types/nodemailer": "6.4.0",
|
||||
"@types/qrcode": "1.3.4",
|
||||
"@types/supertest": "2.0.8",
|
||||
"@types/uuid": "7.0.2",
|
||||
|
||||
@@ -13,8 +13,7 @@ async function disable({ headers, body }: Request, res: Response): Promise<unkno
|
||||
|
||||
const { code } = await mfaSchema.validateAsync(body)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const decodedToken = verify(headers.authorization!)
|
||||
const decodedToken = verify(headers.authorization)
|
||||
const user_id = decodedToken['https://hasura.io/jwt/claims']['x-hasura-user-id']
|
||||
|
||||
try {
|
||||
|
||||
@@ -13,8 +13,7 @@ async function enable({ headers, body }: Request, res: Response): Promise<unknow
|
||||
|
||||
const { code } = await mfaSchema.validateAsync(body)
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const decodedToken = verify(headers.authorization!)
|
||||
const decodedToken = verify(headers.authorization)
|
||||
const user_id = decodedToken['https://hasura.io/jwt/claims']['x-hasura-user-id']
|
||||
|
||||
try {
|
||||
|
||||
@@ -10,8 +10,7 @@ import { verify } from '@shared/jwt'
|
||||
async function generate({ headers }: Request, res: Response): Promise<unknown> {
|
||||
let image_url: string
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const decodedToken = verify(headers.authorization!)
|
||||
const decodedToken = verify(headers.authorization)
|
||||
const user_id = decodedToken['https://hasura.io/jwt/claims']['x-hasura-user-id']
|
||||
|
||||
const { OTP_ISSUER = 'HBP' } = process.env
|
||||
|
||||
@@ -7,6 +7,7 @@ import { insertUser } from '@shared/queries'
|
||||
import { pwnedPassword } from 'hibp'
|
||||
import { registerSchema } from '@shared/schema'
|
||||
import { request } from '@shared/request'
|
||||
// import { sendEmail } from '@shared/email'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
async function register({ body }: Request, res: Response): Promise<unknown> {
|
||||
@@ -30,13 +31,15 @@ async function register({ body }: Request, res: Response): Promise<unknown> {
|
||||
throw Boom.badImplementation()
|
||||
}
|
||||
|
||||
const ticket = uuidv4()
|
||||
|
||||
try {
|
||||
await request(insertUser, {
|
||||
user: {
|
||||
email,
|
||||
active,
|
||||
ticket,
|
||||
username,
|
||||
ticket: uuidv4(),
|
||||
user_accounts: {
|
||||
data: {
|
||||
email,
|
||||
@@ -46,6 +49,14 @@ async function register({ body }: Request, res: Response): Promise<unknown> {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
/*if (!active) {
|
||||
await sendEmail({
|
||||
to: email,
|
||||
subject: 'Hello World',
|
||||
text: `Ticket: ${ticket}`
|
||||
})
|
||||
}*/
|
||||
} catch (err) {
|
||||
throw Boom.badImplementation()
|
||||
}
|
||||
|
||||
@@ -7,8 +7,7 @@ import { request } from '@shared/request'
|
||||
import { verify } from '@shared/jwt'
|
||||
|
||||
async function revoke({ headers }: Request, res: Response): Promise<unknown> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const decodedToken = verify(headers.authorization!)
|
||||
const decodedToken = verify(headers.authorization)
|
||||
const user_id = decodedToken['https://hasura.io/jwt/claims']['x-hasura-user-id']
|
||||
|
||||
try {
|
||||
|
||||
@@ -6,17 +6,33 @@ import { deleteUserById } from '@shared/queries'
|
||||
import { request } from '@shared/request'
|
||||
import { verify } from '@shared/jwt'
|
||||
|
||||
interface HasuraData {
|
||||
delete_private_user_accounts: { affected_rows: number }
|
||||
delete_private_refresh_tokens: { affected_rows: number }
|
||||
delete_users: { affected_rows: number }
|
||||
}
|
||||
|
||||
async function remove({ headers }: Request, res: Response): Promise<unknown> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const decodedToken = verify(headers.authorization!)
|
||||
let hasuraData: HasuraData
|
||||
|
||||
const decodedToken = verify(headers.authorization)
|
||||
const user_id = decodedToken['https://hasura.io/jwt/claims']['x-hasura-user-id']
|
||||
|
||||
try {
|
||||
await request(deleteUserById, { user_id })
|
||||
hasuraData = (await request(deleteUserById, { user_id })) as HasuraData
|
||||
} catch (err) {
|
||||
throw Boom.badImplementation()
|
||||
}
|
||||
|
||||
const deleteUsers = hasuraData.delete_users
|
||||
const deleteAccounts = hasuraData.delete_private_user_accounts
|
||||
|
||||
const doesNotExist = !deleteAccounts.affected_rows || !deleteUsers.affected_rows
|
||||
|
||||
if (doesNotExist) {
|
||||
throw Boom.unauthorized('Invalid or expired JWT token.')
|
||||
}
|
||||
|
||||
return res.status(204).send()
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import { storagePermission } from './rules'
|
||||
import { verify } from '@shared/jwt'
|
||||
|
||||
async function delete_file(req: Request, res: Response): Promise<unknown> {
|
||||
const key = `${req.params[0]}`
|
||||
const key = req.params[0]
|
||||
|
||||
// check storage rules if allowed to get meta info of file
|
||||
const jwt_token = verify(req.headers.authorization)
|
||||
@@ -25,9 +25,7 @@ async function delete_file(req: Request, res: Response): Promise<unknown> {
|
||||
|
||||
try {
|
||||
await s3.deleteObject(params).promise()
|
||||
} catch (e) {
|
||||
console.error('error')
|
||||
console.error({ e })
|
||||
} catch (err) {
|
||||
throw Boom.badImplementation()
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { asyncWrapper } from '@shared/helpers'
|
||||
import { s3 } from '@shared/s3'
|
||||
|
||||
async function get_file(req: Request, res: Response): Promise<void> {
|
||||
const key = `${req.params[0]}`
|
||||
const key = req.params[0]
|
||||
const token = req.query.token
|
||||
|
||||
// get file info
|
||||
@@ -18,10 +18,8 @@ async function get_file(req: Request, res: Response): Promise<void> {
|
||||
|
||||
try {
|
||||
data = await s3.headObject(params).promise()
|
||||
} catch (e) {
|
||||
if (e) {
|
||||
throw Boom.notFound()
|
||||
}
|
||||
} catch (err) {
|
||||
throw Boom.notFound()
|
||||
}
|
||||
|
||||
if (!data?.Metadata) {
|
||||
@@ -35,7 +33,7 @@ async function get_file(req: Request, res: Response): Promise<void> {
|
||||
const stream = s3.getObject(params).createReadStream()
|
||||
|
||||
// forward errors
|
||||
stream.on('error', function error(err) {
|
||||
stream.on('error', err => {
|
||||
console.error(err)
|
||||
throw Boom.badImplementation()
|
||||
})
|
||||
|
||||
@@ -7,7 +7,7 @@ import { storagePermission } from './rules'
|
||||
import { verify } from '@shared/jwt'
|
||||
|
||||
async function get_file(req: Request, res: Response): Promise<unknown> {
|
||||
const key = `${req.params[0]}`
|
||||
const key = req.params[0]
|
||||
|
||||
// check storage rules if allowed to get meta info of file
|
||||
const jwt_token = verify(req.headers.authorization)
|
||||
@@ -26,9 +26,7 @@ async function get_file(req: Request, res: Response): Promise<unknown> {
|
||||
let data
|
||||
try {
|
||||
data = await s3.headObject(params).promise()
|
||||
} catch (e) {
|
||||
console.error('error')
|
||||
console.error({ e })
|
||||
} catch (err) {
|
||||
throw Boom.badImplementation()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +1,13 @@
|
||||
import { Request, Response } from 'express'
|
||||
|
||||
import Boom from '@hapi/boom'
|
||||
import { UploadedFile } from 'express-fileupload'
|
||||
import { asyncWrapper } from '@shared/helpers'
|
||||
import { s3 } from '@shared/s3'
|
||||
import { storagePermission } from './rules'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { verify } from '@shared/jwt'
|
||||
|
||||
interface UploadedFile {
|
||||
/** file name */
|
||||
name: string
|
||||
/** A function to move the file elsewhere on your server */
|
||||
mv(path: string, callback: (err: unknown) => void): void
|
||||
mv(path: string): Promise<void>
|
||||
/** Encoding type of the file */
|
||||
encoding: string
|
||||
/** The mimetype of your file */
|
||||
mimetype: string
|
||||
/** A buffer representation of your file, returns empty buffer in case useTempFiles option was set to true. */
|
||||
data: Buffer
|
||||
/** A path to the temporary file in case useTempFiles option was set to true. */
|
||||
tempFilePath: string
|
||||
/** A boolean that represents if the file is over the size limit */
|
||||
truncated: boolean
|
||||
/** Uploaded size in bytes */
|
||||
size: number
|
||||
/** MD5 checksum of the uploaded file */
|
||||
md5: string
|
||||
}
|
||||
|
||||
async function upload_file(req: Request, res: Response): Promise<unknown> {
|
||||
if (!req.files?.file) {
|
||||
throw Boom.badRequest('No file')
|
||||
@@ -65,9 +44,7 @@ async function upload_file(req: Request, res: Response): Promise<unknown> {
|
||||
|
||||
try {
|
||||
await s3.upload(upload_params).promise()
|
||||
} catch (e) {
|
||||
console.log('error')
|
||||
console.log({ e })
|
||||
} catch (err) {
|
||||
throw Boom.badImplementation()
|
||||
}
|
||||
|
||||
|
||||
30
src/shared/email.ts
Normal file
30
src/shared/email.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import nodemailer from 'nodemailer'
|
||||
|
||||
interface Email {
|
||||
to: string
|
||||
text: string
|
||||
from?: string
|
||||
subject: string
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export async function sendEmail(options: Email): Promise<any> {
|
||||
const { to, text, from = '"noreply" <noreply@example.com>', subject } = options
|
||||
|
||||
const testAccount = await nodemailer.createTestAccount()
|
||||
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: 'smtp.ethereal.email',
|
||||
port: 587,
|
||||
secure: false,
|
||||
auth: {
|
||||
user: testAccount.user,
|
||||
pass: testAccount.pass
|
||||
}
|
||||
})
|
||||
|
||||
const info = await transporter.sendMail({ from, to, subject, text })
|
||||
|
||||
console.log('Message sent: %s', info.messageId)
|
||||
console.log('Preview URL: %s', nodemailer.getTestMessageUrl(info))
|
||||
}
|
||||
12
yarn.lock
12
yarn.lock
@@ -583,6 +583,13 @@
|
||||
version "13.9.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.9.1.tgz#96f606f8cd67fb018847d9b61e93997dabdefc72"
|
||||
|
||||
"@types/nodemailer@6.4.0":
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.0.tgz#d8c039be3ed685c4719a026455555be82c124b74"
|
||||
integrity sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/parse-json@^4.0.0":
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
|
||||
@@ -3718,6 +3725,11 @@ node-pre-gyp@^0.14.0:
|
||||
semver "^5.3.0"
|
||||
tar "^4.4.2"
|
||||
|
||||
nodemailer@6.4.5:
|
||||
version "6.4.5"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.5.tgz#45614c6454d1a947242105eeddae03df87e29916"
|
||||
integrity sha512-NH7aNVQyZLAvGr2+EOto7znvz+qJ02Cb/xpou98ApUt5tEAUSVUxhvHvgV/8I5dhjKTYqUw0nasoKzLNBJKrDQ==
|
||||
|
||||
nopt@^4.0.1:
|
||||
version "4.0.3"
|
||||
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48"
|
||||
|
||||
Reference in New Issue
Block a user