123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- // 临时密钥服务例子
- var bodyParser = require('body-parser');
- var STS = require('qcloud-cos-sts');
- var express = require('express');
- var crypto = require('crypto');
- var pathLib = require('path');
- var fs = require('fs');
- // 配置参数
- var config = {
- secretId: process.env.SecretId,
- secretKey: process.env.SecretKey,
- proxy: process.env.Proxy,
- durationSeconds: 1800,
- bucket: process.env.Bucket,
- region: process.env.Region,
- // 允许操作(上传)的对象前缀,可以根据自己网站的用户登录态判断允许上传的目录,例子: user1/* 或者 * 或者a.jpg
- // 请注意当使用 * 时,可能存在安全风险,详情请参阅:https://cloud.tencent.com/document/product/436/40265
- allowPrefix: '*',
- // 密钥的权限列表
- allowActions: '*',
- };
- // 创建临时密钥服务和用于调试的静态服务
- var app = express();
- var replaceBucketRegion = (filePath) => {
- return (req, res, next) => {
- var content = fs.readFileSync(filePath).toString()
- .replace(/(var config = {\r?\n *Bucket: ')test-1250000000(',\r?\n *Region: ')ap-guangzhou(',?\r?\n};?)/,
- '$1' + config.bucket + '$2' + config.region +'$3');
- content = content.replace("config.Uin = '10001';", "config.Uin = '" + process.env.Uin + "'");
- res.header('Content-Type', 'application/javascript');
- res.send(content);
- };
- };
- app.use('/demo/demo.js', replaceBucketRegion(pathLib.resolve(__dirname, '../demo/demo.js')));
- app.use('/test/test.js', replaceBucketRegion(pathLib.resolve(__dirname, '../test/test.js')));
- app.use('/dist/', express.static(pathLib.resolve(__dirname, '../dist')));
- app.use('/demo/', express.static(pathLib.resolve(__dirname, '../demo')));
- app.use('/test/', express.static(pathLib.resolve(__dirname, '../test')));
- app.all('/', (req, res, next) => res.redirect('/demo/'));
- app.use(bodyParser.json());
- // 格式一:临时密钥接口
- app.all('/sts', function (req, res, next) {
- // TODO 这里根据自己业务需要做好放行判断
- if (config.allowPrefix === '_ALLOW_DIR_/*') {
- res.send({error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀'});
- return;
- }
- // 获取临时密钥
- var AppId = config.bucket.substr(config.bucket.lastIndexOf('-') + 1);
- // 数据万象DescribeMediaBuckets接口需要resource为*,参考 https://cloud.tencent.com/document/product/460/41741
- var policy = {
- 'version': '2.0',
- 'statement': [{
- 'action': config.allowActions,
- 'effect': 'allow',
- 'resource': [
- 'qcs::cos:' + config.region + ':uid/' + AppId + ':' + config.bucket + '/' + config.allowPrefix,
- ],
- }],
- };
- var startTime = Math.round(Date.now() / 1000);
- STS.getCredential({
- secretId: config.secretId,
- secretKey: config.secretKey,
- proxy: config.proxy,
- region: config.region,
- durationSeconds: config.durationSeconds,
- policy: policy,
- }, function (err, tempKeys) {
- if (tempKeys) tempKeys.startTime = startTime;
- res.send(err || tempKeys);
- });
- });
- // // 格式二:临时密钥接口,支持细粒度权限控制
- // // 判断是否允许获取密钥
- // var allowScope = function (scope) {
- // var allow = (scope || []).every(function (item) {
- // return config.allowActions.includes(item.action) &&
- // item.bucket === config.bucket &&
- // item.region === config.region &&
- // (item.prefix || '').startsWith(config.allowPrefix);
- // });
- // return allow;
- // };
- // app.all('/sts-scope', function (req, res, next) {
- // var scope = req.body;
- //
- // // TODO 这里根据自己业务需要做好放行判断
- // if (config.allowPrefix === '_ALLOW_DIR_/*') {
- // res.send({error: '请修改 allowPrefix 配置项,指定允许上传的路径前缀'});
- // return;
- // }
- // // TODO 这里可以判断 scope 细粒度控制权限
- // if (!scope || !scope.length || !allowScope(scope)) return res.send({error: 'deny'});
- //
- // // 获取临时密钥
- // var policy = STS.getPolicy(scope);
- // var startTime = Math.round(Date.now() / 1000);
- // STS.getCredential({
- // secretId: config.secretId,
- // secretKey: config.secretKey,
- // proxy: config.proxy,
- // durationSeconds: config.durationSeconds,
- // policy: policy,
- // }, function (err, tempKeys) {
- // if (tempKeys) tempKeys.startTime = startTime;
- // res.send(err || tempKeys);
- // });
- // });
- //
- // // 用于 PostObject 签名保护
- // app.all('/post-policy', function (req, res, next) {
- // var query = req.query;
- // var now = Math.round(Date.now() / 1000);
- // var exp = now + 900;
- // var qKeyTime = now + ';' + exp;
- // var qSignAlgorithm = 'sha1';
- // var policy = JSON.stringify({
- // 'expiration': new Date(exp * 1000).toISOString(),
- // 'conditions': [
- // // {'acl': query.ACL},
- // // ['starts-with', '$Content-Type', 'image/'],
- // // ['starts-with', '$success_action_redirect', redirectUrl],
- // // ['eq', '$x-cos-server-side-encryption', 'AES256'],
- // {'q-sign-algorithm': qSignAlgorithm},
- // {'q-ak': config.secretId},
- // {'q-sign-time': qKeyTime},
- // {'bucket': config.bucket},
- // {'key': query.key},
- // ]
- // });
- //
- // // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778
- // // 步骤一:生成 SignKey
- // var signKey = crypto.createHmac('sha1', config.secretKey).update(qKeyTime).digest('hex');
- //
- // // 步骤二:生成 StringToSign
- // var stringToSign = crypto.createHash('sha1').update(policy).digest('hex');
- //
- // // 步骤三:生成 Signature
- // var qSignature = crypto.createHmac('sha1', signKey).update(stringToSign).digest('hex');
- //
- // console.log(policy);
- // res.send({
- // policyObj: JSON.parse(policy),
- // policy: Buffer.from(policy).toString('base64'),
- // qSignAlgorithm: qSignAlgorithm,
- // qAk: config.secretId,
- // qKeyTime: qKeyTime,
- // qSignature: qSignature,
- // // securityToken: securityToken, // 如果使用临时密钥,要返回在这个资源 sessionToken 的值
- // });
- // });
- //
- // // 上传限制 Content-Type 示例,对应示例 demo/mime-limit.html
- // var COS = require('cos-nodejs-sdk-v5');
- // var cos = new COS({
- // SecretId: config.secretId,
- // SecretKey: config.secretKey,
- // });
- // app.post('/uploadSign', function (req, res, next) {
- //
- // var T = function (x, n) {
- // return ('0000' + x).slice(-(n || 2));
- // }
- // var guid = function () {
- // var S4 = () => (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
- // return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
- // }
- //
- // // 后端来决定文件名,安全性更高
- // var filename = req.query.filename; // 前端传文件原名,后端来决定上传路径
- // var ext = pathLib.extname(filename);
- // var d = new Date();
- // var key = `images/${d.getFullYear()}/${T(d.getMonth() + 1)}/${T(d.getDate())}/${guid()}${ext}`;
- //
- // // 计算前端可能会用到的多个签名,x-cos-mime-limit: text/plain;img/jpg;img/*
- // var signMap = {};
- // var expires = 7200;
- // var mimeLimit = 'image/*';
- // var host = `${config.bucket}.cos.${config.region}.myqcloud.com`;
- // // 1. ListMultipartUploads 签名
- // signMap.ListMultipartUploads = cos.getAuth({
- // Method: 'GET',
- // Key: '',
- // Expires: expires,
- // Query: { uploads: '', prefix: key },
- // Headers: { host: host },
- // });
- // // 2. ListParts 签名
- // signMap.ListParts = cos.getAuth({
- // Method: 'GET',
- // Key: key,
- // Expires: expires,
- // Headers: { host: host },
- // });
- // // 3. InitiateMultipartUpload 签名
- // signMap.InitiateMultipartUpload = cos.getAuth({
- // Method: 'POST',
- // Key: key,
- // Expires: expires,
- // Query: { uploads: '' },
- // Headers: { host: host },
- // });
- // // 4. UploadPart 签名
- // signMap.UploadPart = cos.getAuth({
- // Method: 'PUT',
- // Key: key,
- // Expires: expires,
- // Headers: { host: host, 'x-cos-mime-limit': mimeLimit },
- // });
- // // 5. CompleteMultipartUpload 签名
- // signMap.CompleteMultipartUpload = cos.getAuth({
- // Method: 'POST',
- // Key: key,
- // Expires: expires,
- // Headers: { host: host },
- // });
- // // 6. PutObject 签名
- // signMap.PutObject = cos.getAuth({
- // Method: 'PUT',
- // Key: key,
- // Expires: expires,
- // Headers: { host: host, 'x-cos-mime-limit': mimeLimit },
- // });
- // res.send({
- // code: 0,
- // host,
- // signMap,
- // bucket: config.bucket,
- // region: config.region,
- // key,
- // mimeLimit,
- // });
- // });
- app.all('*', function (req, res, next) {
- res.send({code: -1, message: '404 Not Found'});
- });
- // 启动签名服务
- app.listen(3000);
- console.log('app is listening at http://127.0.0.1:3000');
|