初始化api

This commit is contained in:
whyour
2021-03-15 21:09:30 +08:00
parent f1f8ece8a2
commit 99a8dc78db
28 changed files with 664 additions and 49 deletions
+42
View File
@@ -0,0 +1,42 @@
import { Router, Request, Response, NextFunction } from 'express';
import { Container } from 'typedi';
import { Logger } from 'winston';
import * as fs from 'fs';
import config from '../config';
import jwt from 'jsonwebtoken';
const route = Router();
export default (app: Router) => {
app.use('/', route);
route.post(
'/auth',
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
let username = req.body.username;
let password = req.body.password;
fs.readFile(config.authConfigFile, 'utf8', function (err, data) {
if (err) console.log(err);
var con = JSON.parse(data);
if (username && password) {
if (username == con.user && password == con.password) {
let token = jwt.sign(
{ username, password },
config.secret as any,
{ expiresIn: 60 * 60 * 24 * 7, algorithm: 'HS384' },
);
res.send({ err: 0, token });
} else {
res.send({ err: 1, msg: config.authError });
}
} else {
res.send({ err: 1, msg: '请输入用户名密码!' });
}
});
} catch (e) {
logger.error('🔥 error: %o', e);
return next(e);
}
},
);
};
+70
View File
@@ -0,0 +1,70 @@
import { Router, Request, Response, NextFunction } from 'express';
import { Container } from 'typedi';
import { Logger } from 'winston';
import * as fs from 'fs';
import config from '../config';
const route = Router();
export default (app: Router) => {
app.use('/', route);
route.get(
'/config/:key',
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
let content = '未找到文件';
switch (req.params.key) {
case 'config':
content = getFileContentByName(config.confFile);
break;
case 'sample':
content = getFileContentByName(config.sampleFile);
break;
case 'crontab':
content = getFileContentByName(config.crontabFile);
break;
case 'shareCode':
let shareCodeFile = getLastModifyFilePath(config.shareCodeDir);
content = getFileContentByName(shareCodeFile);
break;
case 'diy':
content = getFileContentByName(config.diyFile);
break;
default:
break;
}
res.send({ code: 200, content });
} catch (e) {
logger.error('🔥 error: %o', e);
return next(e);
}
},
);
};
function getFileContentByName(fileName) {
if (fs.existsSync(fileName)) {
return fs.readFileSync(fileName, 'utf8');
}
return '';
}
function getLastModifyFilePath(dir) {
var filePath = '';
if (fs.existsSync(dir)) {
var lastmtime = 0;
var arr = fs.readdirSync(dir);
arr.forEach(function (item) {
var fullpath = path.join(dir, item);
var stats = fs.statSync(fullpath);
if (stats.isFile()) {
if (stats.mtimeMs >= lastmtime) {
filePath = fullpath;
}
}
});
}
return filePath;
}
+28
View File
@@ -0,0 +1,28 @@
import { Router, Request, Response, NextFunction } from 'express';
import { Container } from 'typedi';
import CookieService from '../services/cookie';
import { celebrate, Joi } from 'celebrate';
import { Logger } from 'winston';
const route = Router();
export default (app: Router) => {
app.use('/', route);
route.get(
'/qrcode',
async (req: Request, res: Response, next: NextFunction) => {
const logger: Logger = Container.get('logger');
try {
if (req) {
const cookieService = Container.get(CookieService);
const { shici } = await cookieService.getYiYan();
return res.status(200).json({ code: 200, data: shici });
} else {
return res.status(200).json({ err: 1, msg: 'loginFaild' });
}
} catch (e) {
logger.error('🔥 error: %o', e);
return next(e);
}
},
);
};
+12
View File
@@ -0,0 +1,12 @@
import { Router } from 'express';
import auth from './auth';
import cookie from './cookie';
import config from './config';
export default () => {
const app = Router();
auth(app);
cookie(app);
config(app);
return app;
};
+28
View File
@@ -0,0 +1,28 @@
import 'reflect-metadata'; // We need this in order to use @Decorators
import config from './config';
import express from 'express';
import Logger from './loaders/logger';
async function startServer() {
const app = express();
await require('./loaders').default({ expressApp: app });
app
.listen(config.port, () => {
Logger.info(`
################################################
🛡️ Server listening on port: ${config.port} 🛡️
################################################
`);
})
.on('error', (err) => {
Logger.error(err);
process.exit(1);
});
}
startServer();
+44
View File
@@ -0,0 +1,44 @@
import dotenv from 'dotenv';
import path from 'path';
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
const envFound = dotenv.config();
const rootPath = path.resolve(__dirname, '../../');
const confFile = path.join(rootPath, 'config/config.sh');
const sampleFile = path.join(rootPath, 'sample/config.sh.sample');
const crontabFile = path.join(rootPath, 'config/crontab.list');
const confBakDir = path.join(rootPath, 'config/bak/');
const authConfigFile = path.join(rootPath, 'config/auth.json');
const shareCodeDir = path.join(rootPath, 'log/jd_get_share_code/');
const diyFile = path.join(rootPath, 'config/diy.sh');
const logPath = path.join(rootPath, 'log/');
const authError = '错误的用户名密码,请重试';
const loginFaild = '请先登录!';
const configString = 'config sample crontab shareCode diy';
if (envFound.error) {
throw new Error("⚠️ Couldn't find .env file ⚠️");
}
export default {
port: parseInt(process.env.PORT, 10),
secret: process.env.SECRET,
logs: {
level: process.env.LOG_LEVEL || 'silly',
},
api: {
prefix: '/api',
},
configString,
loginFaild,
authError,
logPath,
diyFile,
shareCodeDir,
authConfigFile,
confBakDir,
crontabFile,
sampleFile,
confFile,
};
+27
View File
@@ -0,0 +1,27 @@
export interface ICommon {
_id: string;
value: String;
name: String;
type: Number;
}
export interface ICommonInputDTO {
value: String;
name: String;
type: Number;
}
export enum ShareCodeType {
ddFactory = 1,
ddXw,
jxCfd,
jxFactory,
jxFactoryTuan,
jxNc,
jxStory,
jxCfdGroup,
jdZz,
jdZjdTuan,
didi,
jd818,
}
+7
View File
@@ -0,0 +1,7 @@
export interface IContent {
author: String;
paragraphs: [String];
title: String;
id: String;
created_at: Number;
}
+15
View File
@@ -0,0 +1,15 @@
import { Container } from 'typedi';
import LoggerInstance from './logger';
export default ({ models }: { models: { name: string; model: any }[] }) => {
try {
models.forEach((m) => {
Container.set(m.name, m.model);
});
Container.set('logger', LoggerInstance);
} catch (e) {
LoggerInstance.error('🔥 Error on dependency injector loader: %o', e);
throw e;
}
};
+55
View File
@@ -0,0 +1,55 @@
import { Request, Response, NextFunction, Application } from 'express';
import bodyParser from 'body-parser';
import cors from 'cors';
import routes from '../api';
import config from '../config';
import jwt from 'express-jwt';
export default ({ app }: { app: Application }) => {
app.enable('trust proxy');
app.use(cors());
app.use(bodyParser.json());
app.use(
jwt({ secret: config.secret as string, algorithms: ['HS384'] }).unless({
path: ['/api/auth'],
}),
);
app.use(config.api.prefix, routes());
app.use((req, res, next) => {
const err: any = new Error('Not Found');
err['status'] = 404;
next(err);
});
app.use(
(
err: Error & { status: number },
req: Request,
res: Response,
next: NextFunction,
) => {
if (err.name === 'UnauthorizedError') {
return res.status(err.status).send({ message: err.message }).end();
}
return next(err);
},
);
app.use(
(
err: Error & { status: number },
req: Request,
res: Response,
next: NextFunction,
) => {
res.status(err.status || 500);
res.json({
errors: {
message: err.message,
},
});
},
);
};
+15
View File
@@ -0,0 +1,15 @@
import expressLoader from './express';
import dependencyInjectorLoader from './dependencyInjector';
import Logger from './logger';
export default async ({ expressApp }) => {
Logger.info('✌️ DB loaded and connected!');
await dependencyInjectorLoader({
models: [],
});
Logger.info('✌️ Dependency Injector loaded');
await expressLoader({ app: expressApp });
Logger.info('✌️ Express loaded');
};
+32
View File
@@ -0,0 +1,32 @@
import winston from 'winston';
import config from '../config';
const transports = [];
if (process.env.NODE_ENV !== 'development') {
transports.push(new winston.transports.Console());
} else {
transports.push(
new winston.transports.Console({
format: winston.format.combine(
winston.format.cli(),
winston.format.splat(),
),
}),
);
}
const LoggerInstance = winston.createLogger({
level: config.logs.level,
levels: winston.config.npm.levels,
format: winston.format.combine(
winston.format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss',
}),
winston.format.errors({ stack: true }),
winston.format.splat(),
winston.format.json(),
),
transports,
});
export default LoggerInstance;
+125
View File
@@ -0,0 +1,125 @@
import { Service, Inject } from 'typedi';
import winston from 'winston';
import fetch from 'node-fetch';
@Service()
export default class CookieService {
private cookies: string = '';
private s_token: string = '';
private guid: string = '';
private lsid: string = '';
private lstoken: string = '';
private okl_token: string = '';
private token: string = '';
constructor(@Inject('logger') private logger: winston.Logger) {}
public async getYiYan(): Promise<any> {
return { yiYan: 'test' };
}
private async step1() {
try {
let timeStamp = new Date().getTime();
let url =
'https://plogin.m.jd.com/cgi-bin/mm/new_login_entrance?lang=chs&appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=' +
timeStamp +
'&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport';
const text = await fetch(url, {
method: 'get',
headers: {
Connection: 'Keep-Alive',
'Content-Type': 'application/x-www-form-urlencoded',
Accept: 'application/json, text/plain, */*',
'Accept-Language': 'zh-cn',
Referer:
'https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wq.jd.com/passport/LoginRedirect?state=' +
timeStamp +
'&returnurl=https://home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
Host: 'plogin.m.jd.com',
},
});
this.praseSetCookies(text);
} catch (error) {
this.logger.error(error.response.body);
}
}
private async step2() {
try {
if (this.cookies == '') {
return 0;
}
let timeStamp = new Date().getTime();
let url =
'https://plogin.m.jd.com/cgi-bin/m/tmauthreflogurl?s_token=' +
this.s_token +
'&v=' +
timeStamp +
'&remember=true';
const response = await fetch(url, {
method: 'post',
body: JSON.stringify({
lang: 'chs',
appid: 300,
returnurl:
'https://wqlogin2.jd.com/passport/LoginRedirect?state=' +
timeStamp +
'&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action',
source: 'wq_passport',
}),
headers: {
Connection: 'Keep-Alive',
'Content-Type': 'application/x-www-form-urlencoded; Charset=UTF-8',
Accept: 'application/json, text/plain, */*',
Cookie: this.cookies,
Referer:
'https://plogin.m.jd.com/login/login?appid=300&returnurl=https://wqlogin2.jd.com/passport/LoginRedirect?state=' +
timeStamp +
'&returnurl=//home.m.jd.com/myJd/newhome.action?sceneval=2&ufc=&/myJd/home.action&source=wq_passport',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.111 Safari/537.36',
Host: 'plogin.m.jd.com',
},
}).then((res) => res.json);
// this.token = response.body.token
// this.okl_token = response.headers['set-cookie'][0]
// this.okl_token = this.okl_token.substring(this.okl_token.indexOf("=") + 1, this.okl_token.indexOf(";"))
var qrUrl =
'https://plogin.m.jd.com/cgi-bin/m/tmauth?appid=300&client_type=m&token=' +
this.token;
return qrUrl;
} catch (error) {
console.log(error.response.body);
return 0;
}
}
private praseSetCookies(response: any) {
this.s_token = response.body.s_token;
this.guid = response.headers['set-cookie'][0];
this.guid = this.guid.substring(
this.guid.indexOf('=') + 1,
this.guid.indexOf(';'),
);
this.lsid = response.headers['set-cookie'][2];
this.lsid = this.lsid.substring(
this.lsid.indexOf('=') + 1,
this.lsid.indexOf(';'),
);
this.lstoken = response.headers['set-cookie'][3];
this.lstoken = this.lstoken.substring(
this.lstoken.indexOf('=') + 1,
this.lstoken.indexOf(';'),
);
this.cookies =
'guid=' +
this.guid +
'; lang=chs; lsid=' +
this.lsid +
'; lstoken=' +
this.lstoken +
'; ';
}
}
+9
View File
@@ -0,0 +1,9 @@
import { Document, Model } from 'mongoose';
import { IContent } from '../../interfaces/IContent';
import { ICommon } from '../../interfaces/ICommon';
declare global {
namespace Models {
export type IContentModel = Model<IContent & Document>;
export type ICommonModel = Model<ICommon & Document>;
}
}