├── .gitignore
├── package.json
├── LICENSE.md
├── .github
└── workflows
│ └── npm-publish.yml
├── README.md
└── lib
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "strapi-provider-upload-do",
3 | "version": "3.6.9",
4 | "description": "Digital ocean spaces provider for Strapi upload plugin",
5 | "homepage": "http://strapi.io",
6 | "keywords": [
7 | "upload",
8 | "digitalocean",
9 | "spaces",
10 | "strapi",
11 | "provider"
12 | ],
13 | "directories": {
14 | "lib": "./lib"
15 | },
16 | "main": "./lib",
17 | "dependencies": {
18 | "aws-sdk": "2.1350.0",
19 | "urijs": "1.19.6"
20 | },
21 | "strapi": {
22 | "isProvider": true
23 | },
24 | "author": {
25 | "email": "stanley@hsjm.io",
26 | "name": "Stanley Horwood",
27 | "url": "https://hsjm.io"
28 | },
29 | "repository": {
30 | "type": "git",
31 | "url": "git://github.com/shorwood/strapi-provider-upload-do.git"
32 | },
33 | "bugs": {
34 | "url": "https://github.com/shorwood/strapi-provider-upload-do/issues"
35 | },
36 | "engines": {
37 | "node": ">= 10.0.0",
38 | "npm": ">= 6.0.0"
39 | },
40 | "license": "MIT"
41 | }
42 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2015-2019 Strapi Solutions.
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/.github/workflows/npm-publish.yml:
--------------------------------------------------------------------------------
1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages
3 |
4 | name: Publish Node.js Package
5 |
6 | on: push
7 |
8 | jobs:
9 | build:
10 | name: Building and testing Node.js Package.
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v2
14 | - uses: actions/setup-node@v1
15 | with:
16 | node-version: 12
17 | - run: npm ci
18 | - run: npm test
19 |
20 | publish-npm:
21 | name: Publishing Node.js Package to NPM package registry.
22 | runs-on: ubuntu-latest
23 | steps:
24 | - uses: actions/checkout@v1
25 | - uses: actions/setup-node@v1
26 | with:
27 | node-version: 12
28 | - run: npm install
29 | - run: npm test
30 | - uses: JS-DevTools/npm-publish@v1
31 | with:
32 | registry: https://registry.npmjs.org/
33 | token: ${{ secrets.NPM_TOKEN }}
34 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Strapi Upload Provider for Digital Ocean Spaces
2 | - This provider is a fork of [AdamZikmund's](https://github.com/AdamZikmund) [strapi upload provider](https://github.com/AdamZikmund/strapi-provider-upload-digitalocean) for Digital Ocean spaces.
3 |
4 | This provider will upload to the space using the AWS S3 API.
5 |
6 | ## Parameters
7 | - **key** : [Space access key](https://cloud.digitalocean.com/account/api/tokens)
8 | - **secret** : [Space access secret](https://cloud.digitalocean.com/account/api/tokens)
9 | - **endpoint** : Base URL of the space (e.g. `fra.digitaloceanspaces.com`)
10 | - **space** : Name of the space in the Digital Ocean panel.
11 | - **directory** : Name of the sub-directory you want to store your files in. (Optionnal - e.g. `/example`)
12 | - **cdn** : CDN Endpoint - URL of the cdn of the space (Optionnal - e.g. `cdn.example.com`)
13 |
14 | ## How to use
15 |
16 | 1. Install this package
17 |
18 | ```bash
19 | npm i strapi-provider-upload-do
20 | ```
21 | ```bash
22 | yarn add strapi-provider-upload-do
23 | ```
24 | ```bash
25 | pnpm add strapi-provider-upload-do
26 | ```
27 |
28 | 2. Create or update config in `./config/plugins.js` with content
29 |
30 | ```js
31 | module.exports = ({env}) => ({
32 | // ...
33 | upload: {
34 | config: {
35 | provider: "strapi-provider-upload-do",
36 | providerOptions: {
37 | key: env('DO_SPACE_ACCESS_KEY'),
38 | secret: env('DO_SPACE_SECRET_KEY'),
39 | endpoint: env('DO_SPACE_ENDPOINT'),
40 | space: env('DO_SPACE_BUCKET'),
41 | directory: env('DO_SPACE_DIRECTORY'),
42 | cdn: env('DO_SPACE_CDN'),
43 | }
44 | },
45 | },
46 | // ...
47 | })
48 |
49 | ```
50 |
51 | 3. Create `.env` and add provide Digital Ocean config.
52 |
53 | ```bash
54 | DO_SPACE_ACCESS_KEY=
55 | DO_SPACE_SECRET_KEY=
56 | DO_SPACE_ENDPOINT=
57 | DO_SPACE_BUCKET=
58 | DO_SPACE_DIRECTORY=
59 | DO_SPACE_CDN=
60 | ```
61 |
62 | with values obtained from tutorial:
63 |
64 | > https://www.digitalocean.com/community/tutorials/how-to-create-a-digitalocean-space-and-api-key
65 |
66 | Parameter `DO_SPACE_DIRECTORY` and `DO_SPACE_CDN` is optional and you can ommit them both in `.env` and `settings`.
67 |
68 | ## Resources
69 |
70 | - [MIT License](LICENSE.md)
71 |
72 | ## Links
73 |
74 | - [Strapi website](http://strapi.io/)
75 | - [Strapi community on Slack](http://slack.strapi.io)
76 | - [Strapi news on Twitter](https://twitter.com/strapijs)
77 | - [Strapi docs about upload](https://strapi.io/documentation/3.0.0-beta.x/plugins/upload.html#configuration)
78 |
79 | ## Contributors
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | const AWS = require('aws-sdk');
3 | const URI = require('urijs');
4 | const crypto = require('crypto');
5 |
6 | class FileLocationConverter {
7 | constructor(config) {
8 | this.config = config;
9 | }
10 |
11 | getKey(file) {
12 | const filename = `${file.hash}${file.ext}`;
13 | if (!this.config.directory) return filename;
14 | return `${this.config.directory}/${filename}`;
15 | }
16 |
17 | getUrl(data) {
18 | if (!this.config.cdn) return data.Location;
19 | var parts = {};
20 | URI.parseHost(this.config.cdn, parts);
21 | parts.protocol = "https"; // Force https
22 | parts.path = data.Key;
23 | return URI.build(parts);
24 | }
25 | }
26 |
27 | module.exports = {
28 | provider: "do",
29 | name: "Digital Ocean Spaces",
30 | auth: {
31 | key: {
32 | label: "Key",
33 | type: "text"
34 | },
35 | secret: {
36 | label: "Secret",
37 | type: "text"
38 | },
39 | endpoint: {
40 | label: "Endpoint (e.g. 'fra1.digitaloceanspaces.com')",
41 | type: "text",
42 | },
43 | cdn: {
44 | label: "CDN Endpoint (Optional - e.g. 'https://cdn.space.com')",
45 | type: "text",
46 | },
47 | space: {
48 | label: "Space (e.g. myspace)",
49 | type: "text",
50 | },
51 | directory: {
52 | label: 'Directory (Optional - e.g. directory - place when you want to save files)',
53 | type: 'text'
54 | }
55 | },
56 | init: config => {
57 | const endpoint = new AWS.Endpoint(config.endpoint);
58 | const converter = new FileLocationConverter(config);
59 |
60 | const S3 = new AWS.S3({
61 | endpoint: endpoint,
62 | accessKeyId: config.key,
63 | secretAccessKey: config.secret,
64 | params: {
65 | ACL: 'public-read',
66 | Bucket: config.space,
67 | CacheControl: 'public, max-age=31536000, immutable'
68 | },
69 | });
70 |
71 | const upload = file => new Promise((resolve, reject) => {
72 | //--- Compute the file key.
73 | file.hash = crypto.createHash('md5').update(file.hash).digest("hex");
74 |
75 | //--- Upload the file into the space (technically the S3 Bucket)
76 | S3.upload({
77 | Key: converter.getKey(file),
78 | Body: Buffer.from(file.buffer, "binary"),
79 | ContentType: file.mime
80 | },
81 |
82 | //--- Callback handler
83 | (err, data) => {
84 | if (err) return reject(err);
85 | file.url = converter.getUrl(data);
86 | delete file.buffer;
87 | resolve();
88 | });
89 | });
90 |
91 | return {
92 | upload,
93 |
94 | uploadStream: file => new Promise((resolve, reject) => {
95 | const _buf = [];
96 |
97 | file.stream.on('data', chunk => _buf.push(chunk));
98 | file.stream.on('end', () => {
99 | file.buffer = Buffer.concat(_buf);
100 | resolve(upload(file));
101 | });
102 | file.stream.on('error', err => reject(err));
103 | }),
104 |
105 | delete: file => new Promise((resolve, reject) => {
106 |
107 | //--- Delete the file from the space
108 | S3.deleteObject({
109 | Bucket: config.bucket,
110 | Key: converter.getKey(file),
111 | },
112 |
113 | //--- Callback handler
114 | (err, data) => {
115 | if (err) return reject(err);
116 | else resolve();
117 | })
118 | }
119 | )
120 | }
121 | }
122 | }
123 |
--------------------------------------------------------------------------------