Commit 5a711f4b authored by Geovanny's avatar Geovanny

Added session to keep user logged in. Added functionality to assign a unit to a user

parent 2141fad0
server/database/config.json
server/node_modules/
server/.env
discord/.env
discord/__pycache__
*.pyc
__pycache__
.vscode
\ No newline at end of file
import asyncio
import discord
import discord
from requests import Session
from discord.ext import commands
from unit.manager import UnitManager
from user.manager import UserManager
from util.command_error_handler import CommandErrorHandler
from util.api_requests import Api
from settings import DISCORD_TOKEN
class ConqBot(commands.Bot):
def __init__(self, command_prefix='>'):
super().__init__(command_prefix)
self.id_to_session = {}
async def getUserSession(self, user:discord.User):
if user.id in self.id_to_session:
return self.id_to_session[user.id]
new_session = Session()
await Api.postSession('/user/d-login', {"discordId": user.id}, new_session);
self.id_to_session[user.id] = new_session
return new_session
loop = asyncio.get_event_loop()
bot = commands.Bot(command_prefix='>')
bot = ConqBot(command_prefix='>')
bot.add_cog(CommandErrorHandler(bot))
bot.add_cog(UserManager(bot))
bot.add_cog(UnitManager(bot))
@bot.event
......
......@@ -7,6 +7,7 @@ from unit.model import Unit
from util.api_requests import Api, ApiError
from .unit_parameters import *
from discord_argparse import ArgumentConverter
from util.embed_style import EmbedStyle
class UnitManager(commands.Cog):
......@@ -111,8 +112,6 @@ class UnitManager(commands.Cog):
except ApiError as error:
return await self.handleApiError(ctx, error)
if data==None:
return await ctx.send('No unit found for: ' + unit)
unit_data = Unit(**data)
embed = discord.Embed();
......@@ -159,63 +158,7 @@ class UnitManager(commands.Cog):
await self.createUnitTable(ctx, units_data)
async def createUnitTable(self, ctx, data):
max_rows = 5
max_pages = len(data) // max_rows
rem = len(data) % max_rows
cur_page = 0;
first_run = True
if rem!=0:
max_pages+=1
while True:
if first_run:
embed = self.createUnitPage(data, max_rows*cur_page, max_rows*cur_page + max_rows)
first_run = False
msg = await ctx.send(embed=embed)
reactmoji = []
if max_pages == 1 and cur_page == 0:
pass
elif cur_page == 0:
reactmoji.append('⏩')
elif cur_page == max_pages-1:
reactmoji.append('⏪')
elif cur_page > 0 and cur_page < max_pages-1:
reactmoji.extend(['⏪', '⏩'])
for react in reactmoji:
await msg.add_reaction(react)
def check_react(reaction, user):
if reaction.message.id != msg.id:
return False
if user != ctx.message.author:
return False
if str(reaction.emoji) not in reactmoji:
return False
return True
try:
res, user = await self.bot.wait_for('reaction_add', timeout=30.0, check=check_react)
except asyncio.TimeoutError:
return await msg.clear_reactions()
if '⏪' in str(res.emoji):
cur_page-= 1
embed = self.createUnitPage(data, max_rows*cur_page, max_rows*cur_page + max_rows)
await msg.clear_reactions()
await msg.edit(embed=embed)
if '⏩' in str(res.emoji):
cur_page+= 1
embed = self.createUnitPage(data, max_rows*cur_page, max_rows*cur_page + max_rows)
await msg.clear_reactions()
await msg.edit(embed=embed)
return await EmbedStyle.createPages(self.bot, ctx, data, 5, self.createUnitPage)
def createUnitPage(self, data, minI, maxI):
embed = discord.Embed(color=0x19212d)
......
......@@ -2,7 +2,9 @@ class Unit(object):
def __init__(self, id, name, type, stars=0, hp=0, pap=0, pd=0, sap=0, sd=0, bap=0, bd=0, pdf=0, sdf=0, bdf=0, leadership=0, troop_count=0, hero_level=0, speed=0, range=0, ammo=0, labour=0,
img=None,
vet_img=None):
vet_img=None,
unit_level=0,
elite_flg=None):
self.id = id
self.name = name
self.type = type
......@@ -31,6 +33,9 @@ class Unit(object):
if vet_img == None:
self.vet_img = 'https://www.conquerorsblade.com/static/img/Conqueror.cd5398b.png'
self.unit_level = unit_level
self.elite_flg = elite_flg
@classmethod
def from_dict(cls, **data):
return cls(**data)
......
import asyncio
import discord
import json
from discord.ext import commands
from discord.user import User
from unit.model import Unit
from util.api_requests import Api, ApiError
from util.embed_style import EmbedStyle
from .uu_parameters import *
class UserManager(commands.Cog):
def __init__(self, bot, loop=None):
self.bot = bot
self.loop = loop or asyncio.get_event_loop()
async def handleApiError(self, ctx, error):
return await ctx.send(error.message)
@commands.command()
async def registerUser(self, ctx):
req_body = {'discordId': ctx.message.author.id}
try:
await Api.post('/user/discord-register', req_body)
await ctx.send('Register succesful')
except ApiError as error:
return await self.handleApiError(ctx, error)
@commands.command()
async def removeAssign(self, ctx, term:str):
data = None
try:
session = await self.bot.getUserSession(ctx.message.author)
data = await Api.getSession('/user/unit/{0}'.format(term), session)
except ApiError as error:
return await self.handleApiError(ctx, error)
await ctx.send('Do you want to remove \'{0}\'? Yes to confirm'.format(data['name']))
def check(m):
return m.channel == ctx.channel and m.author == ctx.message.author
msg = ''
try:
msg = await self.bot.wait_for('message', timeout=30.0, check=check)
except asyncio.TimeoutError:
return await ctx.send('Operation aborted')
try:
session = await self.bot.getUserSession(ctx.message.author)
await Api.deleteSession('/user/unit/{0}'.format(data['id']), session)
return await ctx.send('Unit Assignment Removed')
except ApiError as error:
return await self.handleApiError(ctx, error);
@commands.command()
async def modUnit(self, ctx, term:str, *, params:param_converter=param_converter.defaults()):
data = None
try:
session = await self.bot.getUserSession(ctx.message.author)
data = await Api.getSession('/user/unit/{0}'.format(term), session)
except ApiError as error:
return await self.handleApiError(ctx, error)
await ctx.send('Do you want to modify \'{0}\'? Yes to confirm'.format(data['name']))
def check(m):
return m.channel == ctx.channel and m.author == ctx.message.author
msg = ''
try:
msg = await self.bot.wait_for('message', timeout=30.0, check=check)
except asyncio.TimeoutError:
return await ctx.send('Operation aborted')
try:
session = await self.bot.getUserSession(ctx.message.author)
body = params
await Api.putSession('/user/unit/{0}'.format(data['id']), body, session)
return await ctx.send('Unit Modified Successfully')
except ApiError as error:
return await self.handleApiError(ctx, error);
@commands.command()
async def assignUnit(self, ctx, term:str, *, params:param_converter=param_converter.defaults()):
data = None
try:
data = await Api.get('/unit/{0}'.format(term))
except ApiError as error:
return await self.handleApiError(ctx, error)
await ctx.send('Do you want to assign \'{0}\'? Yes to confirm'.format(data['name']))
def check(m):
return m.channel == ctx.channel and m.author == ctx.message.author
msg = ''
try:
msg = await self.bot.wait_for('message', timeout=30.0, check=check)
except asyncio.TimeoutError:
return await ctx.send('Operation aborted')
try:
session = await self.bot.getUserSession(ctx.message.author)
body = params
body['unit_id'] = data['id']
print(body)
await Api.postSession('/user/unit', body, session)
return await ctx.send('Unit Assigned Successfully')
except ApiError as error:
return await self.handleApiError(ctx, error);
@commands.command()
async def myUnits(self, ctx):
try:
session = await self.bot.getUserSession(ctx.message.author)
data = await Api.getSession('/user/units', session)
units_data = []
for item in data['units']:
units_data.append(Unit(**item))
return await EmbedStyle.createPages(self.bot, ctx, units_data, 5, self.createUnitPage)
except ApiError as error:
return await self.handleApiError(ctx, error)
def createUnitPage(self, data, minI, maxI):
embed = discord.Embed(color=0x19212d)
embed.set_author(name='TestBot')
units_str = '';
for i in range(minI, maxI):
if i < len(data):
unit = data[i]
units_str+= '[{0}] {1}\t| {2}\t| {3}\t| {4}\n'.format(unit.id, unit.name, unit.type, unit.stars, unit.unit_level)
embed.add_field(name='id\t| name\t| type\t| stars\t| level', value=units_str)
return embed
from discord_argparse import *
param_converter = ArgumentConverter(
unit_level = OptionalArgument(
str,
doc='Level of Unit',
),
eltie_flg = OptionalArgument(
bool,
doc='Is Unit Elite',
)
)
\ No newline at end of file
......@@ -6,6 +6,7 @@ from settings import API_URL_BASE
class ApiError(Exception):
def __init__(self, error_code:int, message:str=None):
self.error_code = error_code
self.message = message
......@@ -38,27 +39,38 @@ class Api:
return Api.status_code_handling(response)
@staticmethod
async def delete(url, cookies=None):
req_url = API_URL_BASE + url
response = requests.delete(req_url, cookies=cookies)
return Api.status_code_handling(response)
@staticmethod
async def getWithUser(url, uid):
enc_id = Crypto.encrypt(str(uid))
cookies = {'discord_id': enc_id}
print('ENC: ' + enc_id)
return await Api.get(url, cookies)
async def getSession(url, session):
req_url = API_URL_BASE + url
response = session.get(req_url)
return Api.status_code_handling(response)
@staticmethod
async def postWithUser(url, data, uid):
enc_id = Crypto.encrypt(str(uid))
cookies = {'discord_id': enc_id}
print('ENC: ' + enc_id)
return await Api.post(url, data, cookies)
async def postSession(url, data, session):
req_url = API_URL_BASE + url
response = session.post(req_url, json=data)
return Api.status_code_handling(response)
@staticmethod
async def putSession(url, data, session):
req_url = API_URL_BASE + url
response = session.put(req_url, json=data)
return Api.status_code_handling(response)
@staticmethod
async def putWithUser(url, data, uid):
enc_id = Crypto.encrypt(str(uid))
cookies = {'discord_id': enc_id}
print('ENC: ' + enc_id)
return await Api.put(url, data, cookies)
async def deleteSession(url, session):
req_url = API_URL_BASE + url
response = session.delete(req_url)
return Api.status_code_handling(response)
@staticmethod
......@@ -79,7 +91,6 @@ class Api:
elif response.status_code >= 400:
error_str = '[!] [{0}] Bad Request'.format(response.status_code);
print(error_str)
print(content)
raise ApiError(response.status_code, content)
elif response.status_code >= 300:
error_str = '[!] [{0}] Unexpected redirect.'.format(response.status_code)
......
import traceback
import sys
from discord.ext import commands
import discord_argparse.errors as da_errors
......@@ -43,4 +45,8 @@ class CommandErrorHandler(commands.Cog):
if ctx.command.qualified_name == 'tag list': # Check if the command being invoked is 'tag list'
return await ctx.send('I could not find that member. Please try again.')
# All other Errors not returned come here... And we can just print the default TraceBack.
print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr)
traceback.print_exception(type(error), error, error.__traceback__, file=sys.stderr)
......@@ -7,33 +7,40 @@ from settings import ENC_DEC_MEDTHOD
class Crypto:
"""Someday, I will implement encryption and decryption. Today is not that day"""
@staticmethod
def encrypt(str_to_enc):
try:
aes_obj = AES.new(CRYPT_KEY, AES.MODE_CFB, CRYPT_SALT)
hx_enc = aes_obj.encrypt(str_to_enc.encode('utf8'))
mret = b64encode(hx_enc).decode(ENC_DEC_MEDTHOD)
return mret
except ValueError as value_error:
if value_error.args[0] == 'IV must be 16 bytes long':
raise ValueError('Encryption Error: SALT must be 16 characters long')
elif value_error.args[0] == 'AES key must be either 16, 24, or 32 bytes long':
raise ValueError('Encryption Error: Encryption key must be either 16, 24, or 32 characters long')
else:
raise ValueError(value_error)
# try:
# aes_obj = AES.new(CRYPT_KEY, AES.MODE_CFB, CRYPT_SALT)
# hx_enc = aes_obj.encrypt(str_to_enc.encode('utf8'))
# mret = b64encode(hx_enc).decode(ENC_DEC_MEDTHOD)
# return mret
# except ValueError as value_error:
# if value_error.args[0] == 'IV must be 16 bytes long':
# raise ValueError('Encryption Error: SALT must be 16 characters long')
# elif value_error.args[0] == 'AES key must be either 16, 24, or 32 bytes long':
# raise ValueError('Encryption Error: Encryption key must be either 16, 24, or 32 characters long')
# else:
# raise ValueError(value_error)
return base64encode(str_to_enc.encode('utf8')).decode('utf-8')
@staticmethod
def decrypt(enc_str):
try:
aes_obj = AES.new(CRYPT_KEY.encode('utf8'), AES.MODE_CFB, CRYPT_SALT)
str_tmp = b64decode(enc_str.encode(ENC_DEC_MEDTHOD))
str_dec = aes_obj.decrypt(str_tmp)
mret = str_dec.decode(ENC_DEC_MEDTHOD)
return mret
except ValueError as value_error:
if value_error.args[0] == 'IV must be 16 bytes long':
raise ValueError('Decryption Error: SALT must be 16 characters long')
elif value_error.args[0] == 'AES key must be either 16, 24, or 32 bytes long':
raise ValueError('Decryption Error: Encryption key must be either 16, 24, or 32 characters long')
else:
raise ValueError(value_error)
\ No newline at end of file
# try:
# aes_obj = AES.new(CRYPT_KEY.encode('utf8'), AES.MODE_CFB, CRYPT_SALT)
# str_tmp = b64decode(enc_str.encode(ENC_DEC_MEDTHOD))
# str_dec = aes_obj.decrypt(str_tmp)
# mret = str_dec.decode(ENC_DEC_MEDTHOD)
# return mret
# except ValueError as value_error:
# if value_error.args[0] == 'IV must be 16 bytes long':
# raise ValueError('Decryption Error: SALT must be 16 characters long')
# elif value_error.args[0] == 'AES key must be either 16, 24, or 32 bytes long':
# raise ValueError('Decryption Error: Encryption key must be either 16, 24, or 32 characters long')
# else:
# raise ValueError(value_error)
return base64decode(enc_str.encode('utf-8')).decode('utf8')
import discord
from asyncio import TimeoutError
class EmbedStyle:
@staticmethod
async def createPages(bot, ctx, data, max_rows, createRowsFunc):
max_pages = len(data) // max_rows
rem = len(data) % max_rows
cur_page = 0;
first_run = True
if rem!=0:
max_pages+=1
while True:
if first_run:
embed = createRowsFunc(data, max_rows*cur_page, max_rows*cur_page + max_rows)
first_run = False
msg = await ctx.send(embed=embed)
reactmoji = []
if max_pages == 1 and cur_page == 0:
pass
elif cur_page == 0:
reactmoji.append('⏩')
elif cur_page == max_pages-1:
reactmoji.append('⏪')
elif cur_page > 0 and cur_page < max_pages-1:
reactmoji.extend(['⏪', '⏩'])
for react in reactmoji:
await msg.add_reaction(react)
def check_react(reaction, user):
if reaction.message.id != msg.id:
return False
if user != ctx.message.author:
return False
if str(reaction.emoji) not in reactmoji:
return False
return True
try:
res, user = await bot.wait_for('reaction_add', timeout=30.0, check=check_react)
except TimeoutError:
return await msg.clear_reactions()
if '⏪' in str(res.emoji):
cur_page-= 1
embed = createRowsFunc(data, max_rows*cur_page, max_rows*cur_page + max_rows)
await msg.clear_reactions()
await msg.edit(embed=embed)
if '⏩' in str(res.emoji):
cur_page+= 1
embed = createRowsFunc(data, max_rows*cur_page, max_rows*cur_page + max_rows)
await msg.clear_reactions()
await msg.edit(embed=embed)
\ No newline at end of file
'use strict';
const fs = require('fs');
const MySQL = require('promise-mysql');
let config_file = fs.readFileSync('./database/config.json');
let db_config = JSON.parse(config_file);
const ENV = require('../settings');
const db = {}
let connection = MySQL.createConnection(db_config);
let connection = MySQL.createConnection({
host: ENV.DB_HOST,
port: ENV.DB_PORT,
user: ENV.DB_USER,
password: ENV.DB_PASS,
database: ENV.DB_NAME
});
connection.then((con) =>{
console.log('Database Connected');
......
......@@ -3,15 +3,22 @@
const Koa = require('koa');
const Router = require('@koa/router');
const bodyParser = require('koa-body');
const session = require('koa-session')
const auth = require('./util/auth');
const unitsRouter = require('./unit/route');
const userRouter = require('./user/route');
const unitRouter = require('./unit/route');
const SESS_CONFIG = require('./session_config');
const ENV = require('./settings')
const app = new Koa();
const router = new Router();
router.use('/unit', unitsRouter.routes(), unitsRouter.allowedMethods());
app.keys = [ENV.SESS_KEY]
app.use(bodyParser());
app.use(session(SESS_CONFIG, app));
router.use('/unit', unitRouter.routes(), unitRouter.allowedMethods());
router.use('/user', userRouter.routes(), userRouter.allowedMethods());
//app.use(auth());
app.use(router.routes()).use(router.allowedMethods());
......
......@@ -62,6 +62,11 @@
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
"integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8="
},
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"bignumber.js": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz",
......@@ -72,6 +77,15 @@
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz",
"integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg=="
},
"buffer": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz",
"integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
......@@ -136,6 +150,14 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"crc": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz",
"integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==",
"requires": {
"buffer": "^5.1.0"
}
},
"debug": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
......@@ -233,6 +255,11 @@
"safer-buffer": ">= 2.1.2 < 3"
}
},
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"inflation": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz",
......@@ -243,16 +270,36 @@
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"is-class-hotfix": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz",
"integrity": "sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ=="
},
"is-generator-function": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz",
"integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw=="
},
"is-type-of": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/is-type-of/-/is-type-of-1.2.1.tgz",
"integrity": "sha512-uK0kyX9LZYhSDS7H2sVJQJop1UnWPWmo5RvR3q2kFH6AUHYs7sOrVg0b4nyBHw29kRRNFofYN/JbHZDlHiItTA==",
"requires": {
"core-util-is": "^1.0.2",
"is-class-hotfix": "~0.0.6",
"isstream": "~0.1.2"
}
},
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"keygrip": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz",
......@@ -362,6 +409,27 @@
}
}
},
"koa-session": {
"version": "5.13.1",
"resolved": "https://registry.npmjs.org/koa-session/-/koa-session-5.13.1.tgz",
"integrity": "sha512-TfYiun6xiFosyfIJKnEw0aoG5XmLIwM+K3OVWfkz84qY0NP2gbk0F/olRn0/Hrxq0f14s8amHVXeWyKYH3Cx3Q==",
"requires": {
"crc": "^3.4.4",
"debug": "^3.1.0",
"is-type-of": "^1.0.0",
"uuid": "^3.3.2"
},
"dependencies": {
"debug": {
"version": "3.2.6",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"koa-static": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/koa-static/-/koa-static-5.0.0.tgz",
......@@ -639,6 +707,11 @@
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"vary": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
......
......@@ -6,6 +6,7 @@
"fs": "0.0.1-security",
"koa": "^2.11.0",
"koa-body": "^4.1.1",
"koa-session": "^5.13.1",
"koa-static": "^5.0.0",
"promise-mysql": "^4.1.3"
}
......
const CONFIG = {
key: 'conqbl', /** (string) cookie key (default is koa:sess) */