forked from labring/laf
-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(init): 支持内置云函数的导入;增加用户登陆注册、小程序授权、阿里云发短信等内置云函数
- Loading branch information
Showing
15 changed files
with
516 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
const fs = require('fs/promises') | ||
const path = require('path') | ||
|
||
class FunctionLoader { | ||
rootPath = path.join(__dirname, 'functions') | ||
|
||
/** | ||
* 获取函数目录列表 | ||
* @returns {Promise<string[]>} | ||
*/ | ||
async getFunctionDirectoryList() { | ||
const dirs = await fs.readdir(this.rootPath) | ||
return dirs ?? [] | ||
} | ||
|
||
/** | ||
* 获取函数 | ||
* @returns {Promise<any[]>} | ||
*/ | ||
async getFunctions() { | ||
const dirs = await this.getFunctionDirectoryList() | ||
const funcPaths = dirs.map(dir => path.join(this.rootPath, dir)) | ||
const results = [] | ||
for (const fp of funcPaths) { | ||
const r = await this.loadFunction(fp) | ||
results.push(r) | ||
} | ||
return results | ||
} | ||
|
||
/** | ||
* 加载函数 | ||
* @param {string}} func_path | ||
* @returns | ||
*/ | ||
async loadFunction(func_path) { | ||
const codePath = path.join(func_path, 'index.js') | ||
const code = await this.loadFunctionCode(codePath) | ||
|
||
const metaPath = path.join(func_path, 'meta.json') | ||
const meta = await this.loadFunctionMeta(metaPath) | ||
|
||
return { ...meta, code } | ||
} | ||
|
||
/** | ||
* 获取函数代码 | ||
* @param {Promise<string>} file_path | ||
*/ | ||
async loadFunctionCode(file_path) { | ||
const data = await fs.readFile(file_path, 'utf-8') | ||
return data | ||
} | ||
|
||
/** | ||
* 获取函数 meta 信息 | ||
* @param {string} file_path | ||
*/ | ||
async loadFunctionMeta(file_path) { | ||
const data = await fs.readFile(file_path, 'utf-8') | ||
return JSON.parse(data) | ||
} | ||
} | ||
|
||
|
||
const fi = new FunctionLoader() | ||
fi.getFunctions() | ||
.then(console.log) | ||
|
||
|
||
module.exports = { | ||
FunctionLoader | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
|
||
/** | ||
* @body phone string 手机号 | ||
*/ | ||
async function main (ctx) { | ||
const db = less.database() | ||
const phone = ctx.body?.phone | ||
if (!phone) { | ||
return 'Error: invalid phone' | ||
} | ||
|
||
const code = Math.min(Math.floor(1000 + Math.random() * 9000), 9999) | ||
|
||
const r = await sendSMSCode(phone, code) | ||
if (r.data === 'ok') { | ||
await db.collection('verify_code').add({ | ||
type: 'sms', | ||
phone, | ||
code, | ||
event: 'login', | ||
created_at: Date.now() | ||
}) | ||
} | ||
return r | ||
} | ||
|
||
/** | ||
* 发送验证码 | ||
* @return {Promise<string>} | ||
* @see cloud function: aliyun-sms-service | ||
*/ | ||
async function sendSMSCode(phone, code) { | ||
const body = { phone, code } | ||
const r = await less.invoke('aliyun-sms-service', { body }) | ||
return r | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"label": "发送登陆验证码", | ||
"name": "send-login-smscode", | ||
"description": "发送登陆短信验证码", | ||
"enableHTTP": true, | ||
"debugParams": "{\n \"phone\": \"13184211245\"\n}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
|
||
import { v4 as uuidv4 } from 'uuid' | ||
import * as crypto from 'crypto' | ||
const querystring = require('querystring') | ||
|
||
const accessKeyId = 'LTAI5tC3FoH47fQT7oZdcYEw' | ||
const accessKeySecret = 'B7NHLuoFKvrPw8w3QIBZWNn4zrZcpp' | ||
const api_entrypoint = 'https://dysmsapi.aliyuncs.com' | ||
const signName = '灼灼信息' | ||
const templateCode = 'SMS_217850726' | ||
|
||
/** | ||
* @body phone string 手机号 | ||
* @body code string | number 验证码 | ||
*/ | ||
async function main (ctx) { | ||
const phone = ctx.body?.phone | ||
if (!phone) { | ||
return 'error: invalid phone' | ||
} | ||
const code = ctx.body?.code | ||
if (!code) { | ||
return 'error: invalid code' | ||
} | ||
|
||
const params = sortObjectKeys({ | ||
AccessKeyId: accessKeyId, | ||
Action: 'SendSms', | ||
Format: 'json', | ||
SignatureMethod: 'HMAC-SHA1', | ||
SignatureNonce: uuidv4(), | ||
SignatureVersion: '1.0', | ||
Version: '2017-05-25', | ||
Timestamp: (new Date()).toISOString(), | ||
PhoneNumbers: phone, | ||
SignName: signName, | ||
TemplateCode: templateCode, | ||
TemplateParam: `{"code": ${code}}` | ||
}) | ||
|
||
params['Signature'] = specialEncode(sign(params)) | ||
|
||
const query = querystring.stringify(params) | ||
const url = `${api_entrypoint}?${query}` | ||
|
||
try { | ||
const r = await less.fetch(url) | ||
console.log(r.data) | ||
if(r.data?.Code === 'OK') | ||
return 'ok' | ||
else | ||
return r.data | ||
|
||
} catch (err) { | ||
console.log(err) | ||
return 'error: ' + err | ||
} | ||
} | ||
// 签名 | ||
function sign(raw_params) { | ||
const params = encode(raw_params) | ||
|
||
//拼接strToSign | ||
let strToSign = ''; | ||
for (let i in params) { | ||
strToSign += i + '=' + params[i] + '&'; | ||
} | ||
strToSign = strToSign.substr(0, strToSign.length - 1); | ||
strToSign = "GET&" + encodeURIComponent('/') + '&' + encodeURIComponent(strToSign); | ||
|
||
// 阿里云签名是要求 基于 hash 的原始二进制值 进行 base64编码 | ||
const ret = crypto.createHmac('sha1', accessKeySecret + '&') | ||
.update(strToSign) | ||
.digest('base64') | ||
|
||
return ret | ||
} | ||
|
||
//对各个参数进行字典序升序排序 | ||
function sortObjectKeys(obj) { | ||
const tmp = {}; | ||
Object.keys(obj).sort().forEach(k => tmp[k] = obj[k]) | ||
return tmp; | ||
} | ||
|
||
|
||
//对排序之后的参数进行 uriencode + POP 编码 | ||
function encode(params) { | ||
const obj = {} | ||
//对urlencode之后的特殊字符进行替换 | ||
for (let i in params) { | ||
const str = encodeURIComponent(params[i]) | ||
obj[i] = specialEncode(str) | ||
} | ||
return obj | ||
} | ||
|
||
// 阿里云的特殊编码(POP编码) | ||
function specialEncode(encoded) { | ||
if (encoded.indexOf('+')) { | ||
encoded.replace("+", "%20"); | ||
} else if (str.indexOf('*')) { | ||
encoded.replace("*", "%2A"); | ||
} else if (str.indexOf('%7E')) { | ||
encoded.replace("%7E", "~"); | ||
} | ||
return encoded | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"label": "aliyun-sms-service", | ||
"name": "aliyun-sms-service", | ||
"description": "阿里云通信-发短信内部调用服务,不开启外网访问", | ||
"enableHTTP": false, | ||
"debugParams": "{\n \"phone\": \"13184211245\",\n \"code\": \"1234\"\n}" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
|
||
|
||
exports.main = async function (ctx) { | ||
console.log(ctx) | ||
|
||
return 'ok' | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
{ | ||
"label": "测试", | ||
"name": "test", | ||
"description": "", | ||
"enableHTTP": true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import * as crypto from 'crypto' | ||
|
||
/** | ||
* @body username string 用户名 | ||
* @body password string 密码 | ||
*/ | ||
export async function main(ctx) { | ||
const db = less.database() | ||
|
||
// 参数验证 | ||
const { username, password } = ctx.body | ||
if (!username || !password) { | ||
return { code: 1, error: 'invalid phone or password' } | ||
} | ||
|
||
// 验证用户名是否存在 | ||
const { data: user } = await db.collection('users') | ||
.where({ username }) | ||
.getOne() | ||
|
||
if (!user) { | ||
return {code: 1, error: 'invalid username or password'} | ||
} | ||
|
||
// 验证密码是否正确 | ||
const ret = await db.collection('password') | ||
.where({ uid: user._id, password: hashPassword(password), type: 'login' }) | ||
.count() | ||
|
||
if (ret.total > 0) { | ||
|
||
// 默认 token 有效期为 7 天 | ||
const expire = Math.floor(Date.now() / 1000) + 60 * 60 * 24 * 7 | ||
const payload = { | ||
uid: user._id, | ||
type: 'user', | ||
exp: expire | ||
} | ||
const access_token = less.getToken(payload) | ||
return { | ||
code: 0, | ||
data: { | ||
access_token, | ||
user, | ||
uid: user._id, | ||
expire | ||
} | ||
} | ||
} | ||
|
||
return { code: 1, error: 'invalid username or password' } | ||
} | ||
|
||
/** | ||
* @param {string} content | ||
* @return {string} | ||
*/ | ||
function hashPassword(content) { | ||
return crypto | ||
.createHash('sha256') | ||
.update(content) | ||
.digest('hex') | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"label": "用户密码登陆", | ||
"name": "user-passwd-login", | ||
"description": "用户密码登陆", | ||
"enableHTTP": true, | ||
"debugParams": "{\n \"username\": \"less\",\n \"password\": \"less123\"\n}" | ||
} |
Oops, something went wrong.