picgo-plugin-s3 1.1.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "parser": "@typescript-eslint/parser",
3
+ "extends": [
4
+ "eslint:recommended",
5
+ "plugin:@typescript-eslint/recommended",
6
+ "prettier"
7
+ ],
8
+ "plugins": ["prettier", "@typescript-eslint"],
9
+ "env": {
10
+ "es6": true,
11
+ "node": true
12
+ },
13
+ "rules": {
14
+ "prettier/prettier": [
15
+ "error",
16
+ {
17
+ "semi": false
18
+ }
19
+ ]
20
+ }
21
+ }
package/README.md CHANGED
@@ -19,17 +19,19 @@ GUI 直接搜索 _S3_ 下载即可,Core 版执行 `picgo add s3` 安装。
19
19
  picgo set uploader aws-s3
20
20
  ```
21
21
 
22
- | Key | 说明 | 例子 |
23
- | ----------------- | ----------------------------- | ---------------------------------- |
24
- | `accessKeyID` | AWS 凭证 ID | |
25
- | `secretAccessKey` | AWS 凭证密钥 | |
26
- | `bucketName` | S3 桶名称 | `gallery` |
27
- | `uploadPath` | 上传路径 | `{year}/{month}/{fullName}` |
28
- | `urlPrefix` | 最终生成图片 URL 的自定义前缀 | `https://img.example.com/my-blog/` |
29
- | `endpoint` | 指定自定义终端节点 | `s3.us-west-2.amazonaws.com` |
30
- | `region` | 指定执行服务请求的区域 | `us-west-1` |
31
- | `pathStyleAccess` | 是否启用 S3 Path style | 默认为 `false`,使用 minio 请设置为 `true` |
32
- | `acl` | 访问控制列表,上传资源的访问策略 | 默认为 `public-read` |
22
+ | Key | 说明 | 例子 |
23
+ | -------------------- | ----------------------------------------------------------------------- | -------------------------------------------------------- |
24
+ | `accessKeyID` | AWS 凭证 ID | |
25
+ | `secretAccessKey` | AWS 凭证密钥 | |
26
+ | `bucketName` | S3 桶名称 | `gallery` |
27
+ | `uploadPath` | 上传路径 | `{year}/{month}/{fullName}` |
28
+ | `urlPrefix` | 最终生成图片 URL 的自定义前缀 | `https://img.example.com/my-blog/` |
29
+ | `endpoint` | 指定自定义终端节点 | `s3.us-west-2.amazonaws.com` |
30
+ | `region` | 指定执行服务请求的区域 | `us-west-1` |
31
+ | `pathStyleAccess` | 是否启用 S3 Path style | 默认为 `false`,使用 minio 请设置为 `true` |
32
+ | `rejectUnauthorized` | 是否拒绝无效 TLS 证书连接 | 默认为 `true`,如上传失败日志显示证书问题可设置为`false` |
33
+ | `bucketEndpoint` | 提供的 Endpoint 是否针对单个存储桶(如果它针对根 API 端点,则为 false) | 默认为 `false` |
34
+ | `acl` | 访问控制列表,上传资源的访问策略 | 默认为 `public-read` |
33
35
 
34
36
  **上传路径支持 payload:**
35
37
 
@@ -0,0 +1,13 @@
1
+ export interface IS3UserConfig {
2
+ accessKeyID: string;
3
+ secretAccessKey: string;
4
+ bucketName: string;
5
+ uploadPath: string;
6
+ region?: string;
7
+ endpoint?: string;
8
+ urlPrefix?: string;
9
+ pathStyleAccess?: boolean;
10
+ rejectUnauthorized?: boolean;
11
+ bucketEndpoint?: boolean;
12
+ acl?: string;
13
+ }
package/dist/config.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import picgo from 'picgo';
1
+ import picgo from "picgo";
2
2
  declare const _default: (ctx: picgo) => {
3
3
  register: () => void;
4
4
  };
package/dist/index.js CHANGED
@@ -7,108 +7,126 @@ const utils_1 = require("./utils");
7
7
  module.exports = (ctx) => {
8
8
  const config = (ctx) => {
9
9
  const defaultConfig = {
10
- accessKeyID: '',
11
- secretAccessKey: '',
12
- bucketName: '',
13
- uploadPath: '{year}/{month}/{md5}.{extName}',
10
+ accessKeyID: "",
11
+ secretAccessKey: "",
12
+ bucketName: "",
13
+ uploadPath: "{year}/{month}/{md5}.{extName}",
14
14
  pathStyleAccess: false,
15
- acl: 'public-read'
15
+ rejectUnauthorized: true,
16
+ bucketEndpoint: false,
17
+ acl: "public-read",
16
18
  };
17
- let userConfig = ctx.getConfig('picBed.aws-s3');
19
+ let userConfig = ctx.getConfig("picBed.aws-s3");
18
20
  userConfig = Object.assign(Object.assign({}, defaultConfig), (userConfig || {}));
19
21
  return [
20
22
  {
21
- name: 'accessKeyID',
22
- type: 'input',
23
+ name: "accessKeyID",
24
+ type: "input",
23
25
  default: userConfig.accessKeyID,
24
26
  required: true,
25
- message: 'access key id',
26
- alias: '应用密钥 ID'
27
+ message: "access key id",
28
+ alias: "应用密钥 ID",
27
29
  },
28
30
  {
29
- name: 'secretAccessKey',
30
- type: 'password',
31
+ name: "secretAccessKey",
32
+ type: "password",
31
33
  default: userConfig.secretAccessKey,
32
34
  required: true,
33
- message: 'secret access key',
34
- alias: '应用密钥'
35
+ message: "secret access key",
36
+ alias: "应用密钥",
35
37
  },
36
38
  {
37
- name: 'bucketName',
38
- type: 'input',
39
+ name: "bucketName",
40
+ type: "input",
39
41
  default: userConfig.bucketName,
40
42
  required: true,
41
- alias: ''
43
+ alias: "",
42
44
  },
43
45
  {
44
- name: 'uploadPath',
45
- type: 'input',
46
+ name: "uploadPath",
47
+ type: "input",
46
48
  default: userConfig.uploadPath,
47
49
  required: true,
48
- alias: '文件路径'
50
+ alias: "文件路径",
49
51
  },
50
52
  {
51
- name: 'acl',
52
- type: 'input',
53
+ name: "acl",
54
+ type: "input",
53
55
  default: userConfig.acl,
54
- message: '文件访问权限',
56
+ message: "文件访问权限",
55
57
  required: true,
56
- alias: '权限'
58
+ alias: "权限",
57
59
  },
58
60
  {
59
- name: 'region',
60
- type: 'input',
61
+ name: "region",
62
+ type: "input",
61
63
  default: userConfig.region,
62
64
  required: false,
63
- alias: '地区'
65
+ alias: "地区",
64
66
  },
65
67
  {
66
- name: 'endpoint',
67
- type: 'input',
68
+ name: "endpoint",
69
+ type: "input",
68
70
  default: userConfig.endpoint,
69
71
  required: false,
70
- alias: '自定义节点'
72
+ alias: "自定义节点",
71
73
  },
72
74
  {
73
- name: 'urlPrefix',
74
- type: 'input',
75
+ name: "urlPrefix",
76
+ type: "input",
75
77
  default: userConfig.urlPrefix,
76
- message: 'https://img.example.com/bucket-name/',
78
+ message: "https://img.example.com/bucket-name/",
77
79
  required: false,
78
- alias: '自定义域名'
80
+ alias: "自定义域名",
79
81
  },
80
82
  {
81
- name: 'pathStyleAccess',
82
- type: 'confirm',
83
+ name: "pathStyleAccess",
84
+ type: "confirm",
83
85
  default: userConfig.pathStyleAccess || false,
84
- message: 'enable path-style-access or not',
86
+ message: "enable path-style-access or not",
85
87
  required: false,
86
- alias: 'PathStyleAccess'
88
+ alias: "PathStyleAccess",
87
89
  },
88
90
  {
89
- name: 'acl',
90
- type: 'input',
91
- default: userConfig.acl || 'public-read',
92
- message: '上传资源的访问策略',
91
+ name: "rejectUnauthorized",
92
+ type: "confirm",
93
+ default: userConfig.rejectUnauthorized || true,
94
+ message: "是否拒绝无效TLS证书连接",
93
95
  required: false,
94
- alias: 'ACL 访问控制列表'
95
- }
96
+ alias: "rejectUnauthorized",
97
+ },
98
+ {
99
+ name: "bucketEndpoint",
100
+ type: "confirm",
101
+ default: userConfig.bucketEndpoint || false,
102
+ message: "提供的Endpoint是否针对单个存储桶(如果它针对根 API 端点,则为 false)",
103
+ required: false,
104
+ alias: "bucketEndpoint",
105
+ },
106
+ {
107
+ name: "acl",
108
+ type: "input",
109
+ default: userConfig.acl || "public-read",
110
+ message: "上传资源的访问策略",
111
+ required: false,
112
+ alias: "ACL 访问控制列表",
113
+ },
96
114
  ];
97
115
  };
98
116
  const handle = async (ctx) => {
99
- let userConfig = ctx.getConfig('picBed.aws-s3');
117
+ const userConfig = ctx.getConfig("picBed.aws-s3");
100
118
  if (!userConfig) {
101
119
  throw new Error("Can't find amazon s3 uploader config");
102
120
  }
103
121
  if (userConfig.urlPrefix) {
104
- userConfig.urlPrefix = userConfig.urlPrefix.replace(/\/?$/, '');
122
+ userConfig.urlPrefix = userConfig.urlPrefix.replace(/\/?$/, "");
105
123
  }
106
- const client = uploader_1.default.createS3Client(userConfig.accessKeyID, userConfig.secretAccessKey, userConfig.region, userConfig.endpoint, userConfig.pathStyleAccess);
124
+ const client = uploader_1.default.createS3Client(userConfig);
107
125
  const output = ctx.output;
108
- const tasks = output.map((item, idx) => uploader_1.default.createUploadTask(client, userConfig.bucketName, utils_1.formatPath(item, userConfig.uploadPath), item, idx, userConfig.acl));
126
+ const tasks = output.map((item, idx) => uploader_1.default.createUploadTask(client, userConfig.bucketName, (0, utils_1.formatPath)(item, userConfig.uploadPath), item, idx, userConfig.acl));
109
127
  try {
110
128
  const results = await Promise.all(tasks);
111
- for (let result of results) {
129
+ for (const result of results) {
112
130
  const { index, url, imgURL } = result;
113
131
  delete output[index].buffer;
114
132
  delete output[index].base64Image;
@@ -122,24 +140,24 @@ module.exports = (ctx) => {
122
140
  return ctx;
123
141
  }
124
142
  catch (err) {
125
- ctx.log.error('上传到 Amazon S3 发生错误,请检查配置是否正确');
143
+ ctx.log.error("上传到 Amazon S3 发生错误,请检查配置是否正确");
126
144
  ctx.log.error(err);
127
- ctx.emit('notification', {
128
- title: 'Amazon S3 上传错误',
129
- body: '请检查配置是否正确',
130
- text: ''
145
+ ctx.emit("notification", {
146
+ title: "Amazon S3 上传错误",
147
+ body: "请检查配置是否正确",
148
+ text: "",
131
149
  });
132
150
  throw err;
133
151
  }
134
152
  };
135
153
  const register = () => {
136
- ctx.helper.uploader.register('aws-s3', {
154
+ ctx.helper.uploader.register("aws-s3", {
137
155
  handle,
138
156
  config,
139
- name: 'Amazon S3'
157
+ name: "Amazon S3",
140
158
  });
141
159
  };
142
160
  return {
143
- register
161
+ register,
144
162
  };
145
163
  };
@@ -1,12 +1,13 @@
1
- import AWS from 'aws-sdk';
2
- import { IImgInfo } from 'picgo/dist/src/types';
1
+ import S3 from "aws-sdk/clients/s3";
2
+ import { IImgInfo } from "picgo/dist/src/types";
3
+ import { IS3UserConfig } from "./config";
3
4
  export interface IUploadResult {
4
5
  url: string;
5
6
  imgURL: string;
6
7
  index: number;
7
8
  }
8
- declare function createS3Client(accessKeyID: string, secretAccessKey: string, region: string, endpoint: string, pathStyleAccess: boolean): AWS.S3;
9
- declare function createUploadTask(s3: AWS.S3, bucketName: string, path: string, item: IImgInfo, index: number, acl: string): Promise<IUploadResult>;
9
+ declare function createS3Client(opts: IS3UserConfig): S3;
10
+ declare function createUploadTask(s3: S3, bucketName: string, path: string, item: IImgInfo, index: number, acl: string): Promise<IUploadResult>;
10
11
  declare const _default: {
11
12
  createS3Client: typeof createS3Client;
12
13
  createUploadTask: typeof createUploadTask;
package/dist/uploader.js CHANGED
@@ -3,45 +3,60 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const aws_sdk_1 = __importDefault(require("aws-sdk"));
6
+ const s3_1 = __importDefault(require("aws-sdk/clients/s3"));
7
7
  const utils_1 = require("./utils");
8
- function createS3Client(accessKeyID, secretAccessKey, region, endpoint, pathStyleAccess) {
9
- const s3 = new aws_sdk_1.default.S3({
10
- region,
11
- endpoint,
12
- accessKeyId: accessKeyID,
13
- secretAccessKey: secretAccessKey,
14
- s3ForcePathStyle: pathStyleAccess
8
+ function createS3Client(opts) {
9
+ const endpointURL = new URL(opts.endpoint);
10
+ const sslEnabled = endpointURL.protocol === "https";
11
+ const http = sslEnabled ? require("https") : require("http");
12
+ const s3 = new s3_1.default({
13
+ region: opts.region,
14
+ endpoint: opts.endpoint,
15
+ accessKeyId: opts.accessKeyID,
16
+ secretAccessKey: opts.secretAccessKey,
17
+ s3ForcePathStyle: opts.pathStyleAccess,
18
+ s3BucketEndpoint: opts.bucketEndpoint,
19
+ sslEnabled: sslEnabled,
20
+ httpOptions: {
21
+ agent: new http.Agent({
22
+ rejectUnauthorized: opts.rejectUnauthorized,
23
+ }),
24
+ },
15
25
  });
16
26
  return s3;
17
27
  }
18
28
  function createUploadTask(s3, bucketName, path, item, index, acl) {
19
- return new Promise(async (resolve, reject) => {
29
+ return new Promise((resolve, reject) => {
20
30
  if (!item.buffer && !item.base64Image) {
21
- reject(new Error('undefined image'));
31
+ reject(new Error("undefined image"));
22
32
  }
23
- const { body, contentType, contentEncoding } = await utils_1.extractInfo(item);
24
- const opts = {
25
- Key: path,
26
- Bucket: bucketName,
27
- ACL: acl,
28
- Body: body,
29
- ContentType: contentType,
30
- ContentEncoding: contentEncoding,
31
- };
32
- s3.upload(opts)
33
- .promise()
34
- .then((result) => {
35
- resolve({
36
- url: result.Location,
37
- imgURL: result.Key,
38
- index
39
- });
33
+ (0, utils_1.extractInfo)(item)
34
+ .then(({ body, contentType, contentEncoding }) => {
35
+ const opts = {
36
+ Key: path,
37
+ Bucket: bucketName,
38
+ ACL: acl,
39
+ Body: body,
40
+ ContentType: contentType,
41
+ ContentEncoding: contentEncoding,
42
+ };
43
+ s3.upload(opts)
44
+ .promise()
45
+ .then((result) => {
46
+ resolve({
47
+ url: result.Location,
48
+ imgURL: result.Key,
49
+ index,
50
+ });
51
+ })
52
+ .catch((err) => reject(err));
40
53
  })
41
- .catch((err) => reject(err));
54
+ .catch((err) => {
55
+ reject(err);
56
+ });
42
57
  });
43
58
  }
44
59
  exports.default = {
45
60
  createS3Client,
46
- createUploadTask
61
+ createUploadTask,
47
62
  };
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { IImgInfo } from 'picgo/dist/src/types';
2
+ import { IImgInfo } from "picgo/dist/src/types";
3
3
  export declare function formatPath(info: IImgInfo, format?: string): string;
4
4
  export declare function extractInfo(info: IImgInfo): Promise<{
5
5
  body?: Buffer;
package/dist/utils.js CHANGED
@@ -29,36 +29,34 @@ class FileNameGenerator {
29
29
  return this.info.fileName;
30
30
  }
31
31
  fileName() {
32
- return this.info.fileName.replace(this.info.extname, '');
32
+ return this.info.fileName.replace(this.info.extname, "");
33
33
  }
34
34
  extName() {
35
- return this.info.extname.replace('.', '');
35
+ return this.info.extname.replace(".", "");
36
36
  }
37
37
  md5() {
38
- return crypto_1.default.createHash('md5').update(this.imgBuffer()).digest('hex');
38
+ return crypto_1.default.createHash("md5").update(this.imgBuffer()).digest("hex");
39
39
  }
40
40
  sha1() {
41
- return crypto_1.default.createHash('sha1').update(this.imgBuffer()).digest('hex');
41
+ return crypto_1.default.createHash("sha1").update(this.imgBuffer()).digest("hex");
42
42
  }
43
43
  sha256() {
44
- return crypto_1.default.createHash('sha256').update(this.imgBuffer()).digest('hex');
44
+ return crypto_1.default.createHash("sha256").update(this.imgBuffer()).digest("hex");
45
45
  }
46
46
  imgBuffer() {
47
- return this.info.base64Image
48
- ? this.info.base64Image
49
- : this.info.buffer;
47
+ return this.info.base64Image ? this.info.base64Image : this.info.buffer;
50
48
  }
51
49
  }
52
50
  FileNameGenerator.fields = [
53
- 'year',
54
- 'month',
55
- 'day',
56
- 'fullName',
57
- 'fileName',
58
- 'extName',
59
- 'md5',
60
- 'sha1',
61
- 'sha256'
51
+ "year",
52
+ "month",
53
+ "day",
54
+ "fullName",
55
+ "fileName",
56
+ "extName",
57
+ "md5",
58
+ "sha1",
59
+ "sha256",
62
60
  ];
63
61
  function formatPath(info, format) {
64
62
  if (!format) {
@@ -66,8 +64,8 @@ function formatPath(info, format) {
66
64
  }
67
65
  const fileNameGenerator = new FileNameGenerator(info);
68
66
  let formatPath = format;
69
- for (let key of FileNameGenerator.fields) {
70
- const re = new RegExp(`{${key}}`, 'g');
67
+ for (const key of FileNameGenerator.fields) {
68
+ const re = new RegExp(`{${key}}`, "g");
71
69
  formatPath = formatPath.replace(re, fileNameGenerator[key]());
72
70
  }
73
71
  return formatPath;
@@ -75,12 +73,12 @@ function formatPath(info, format) {
75
73
  exports.formatPath = formatPath;
76
74
  async function extractInfo(info) {
77
75
  var _a;
78
- let result = {};
76
+ const result = {};
79
77
  if (info.base64Image) {
80
- const body = info.base64Image.replace(/^data:[/\w]+;base64,/, '');
78
+ const body = info.base64Image.replace(/^data:[/\w]+;base64,/, "");
81
79
  result.contentType = (_a = info.base64Image.match(/[^:]\w+\/[\w-+\d.]+(?=;|,)/)) === null || _a === void 0 ? void 0 : _a[0];
82
- result.body = Buffer.from(body, 'base64');
83
- result.contentEncoding = 'base64';
80
+ result.body = Buffer.from(body, "base64");
81
+ result.contentEncoding = "base64";
84
82
  }
85
83
  else {
86
84
  if (info.extname) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "picgo-plugin-s3",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "description": "picgo amazon s3 uploader",
5
5
  "main": "dist/index.js",
6
6
  "publishConfig": {
@@ -27,17 +27,15 @@
27
27
  "author": "WayJam So",
28
28
  "license": "MIT",
29
29
  "devDependencies": {
30
- "@types/node": "^10.10.1",
31
- "eslint": "^5.0.1",
32
- "eslint-config-standard": "^11.0.0",
33
- "eslint-plugin-import": "^2.13.0",
34
- "eslint-plugin-node": "^6.0.1",
35
- "eslint-plugin-promise": "^3.8.0",
36
- "eslint-plugin-standard": "^3.1.0",
30
+ "@types/node": "^18.7.23",
31
+ "@typescript-eslint/eslint-plugin": "^5.38.1",
32
+ "@typescript-eslint/parser": "^5.38.1",
33
+ "eslint": "^8.25.0",
34
+ "eslint-config-prettier": "^8.5.0",
35
+ "eslint-plugin-prettier": "^4.2.1",
37
36
  "picgo": "^1.4.0 >1.4.16",
38
- "tslint": "^5.10.0",
39
- "tslint-config-standard": "^7.1.0",
40
- "typescript": "^3.7.3"
37
+ "prettier": "^2.7.1",
38
+ "typescript": "^4.8.4"
41
39
  },
42
40
  "dependencies": {
43
41
  "aws-sdk": "^2.839.0",