├── .env.example
├── .github
└── workflows
│ └── release.yml
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── lib
└── index.js
├── package.json
├── public
├── banner.png
├── filebase-provider.png
├── fleek-provider.png
├── lighthouse-provider.png
├── pinata-provider.png
├── screenshot.png
└── web3-provider.png
└── test
└── index.test.js
/.env.example:
--------------------------------------------------------------------------------
1 | FILEBASE_KEY=""
2 | FILEBASE_SECRET=""
3 | FILEBASE_BUCKET=""
4 |
5 | PINATA_JWT=""
6 |
7 | FLEEK_KEY=""
8 | FLEEK_SECRET=""
9 | FLEEK_BUCKET=""
10 |
11 | WEB3_TOKEN=""
12 |
13 | LIGHTHOUSE_TOKEN=""
14 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | push:
5 | branches: [main]
6 |
7 | jobs:
8 | publish-npm:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - uses: actions/checkout@v3
12 | - uses: actions/setup-node@v3
13 | with:
14 | node-version: 16
15 | registry-url: https://registry.npmjs.org/
16 | - run: npm install -g yarn
17 | - run: yarn install --frozen-lockfile
18 | - run: yarn publish
19 | env:
20 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ############################
2 | # OS X
3 | ############################
4 |
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | Icon
9 | .Spotlight-V100
10 | .Trashes
11 | ._*
12 |
13 |
14 | ############################
15 | # Linux
16 | ############################
17 |
18 | *~
19 |
20 |
21 | ############################
22 | # Windows
23 | ############################
24 |
25 | Thumbs.db
26 | ehthumbs.db
27 | Desktop.ini
28 | $RECYCLE.BIN/
29 | *.cab
30 | *.msi
31 | *.msm
32 | *.msp
33 |
34 |
35 | ############################
36 | # Packages
37 | ############################
38 |
39 | *.7z
40 | *.csv
41 | *.dat
42 | *.dmg
43 | *.gz
44 | *.iso
45 | *.jar
46 | *.rar
47 | *.tar
48 | *.zip
49 | *.com
50 | *.class
51 | *.dll
52 | *.exe
53 | *.o
54 | *.seed
55 | *.so
56 | *.swo
57 | *.swp
58 | *.swn
59 | *.swm
60 | *.out
61 | *.pid
62 | *.lock
63 |
64 |
65 | ############################
66 | # Logs and databases
67 | ############################
68 |
69 | .tmp
70 | *.log
71 | *.sql
72 | *.sqlite
73 |
74 |
75 | ############################
76 | # Misc.
77 | ############################
78 |
79 | *#
80 | .idea
81 | nbproject
82 |
83 |
84 | ############################
85 | # Node.js
86 | ############################
87 |
88 | lib-cov
89 | lcov.info
90 | pids
91 | logs
92 | results
93 | build
94 | node_modules
95 | .node_history
96 | package-lock.json
97 | .env
98 | yarn.lock
99 | .txt
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | ############################
2 | # OS X
3 | ############################
4 |
5 | .DS_Store
6 | .AppleDouble
7 | .LSOverride
8 | Icon
9 | .Spotlight-V100
10 | .Trashes
11 | ._*
12 |
13 |
14 | ############################
15 | # Linux
16 | ############################
17 |
18 | *~
19 |
20 |
21 | ############################
22 | # Windows
23 | ############################
24 |
25 | Thumbs.db
26 | ehthumbs.db
27 | Desktop.ini
28 | $RECYCLE.BIN/
29 | *.cab
30 | *.msi
31 | *.msm
32 | *.msp
33 |
34 |
35 | ############################
36 | # Packages
37 | ############################
38 |
39 | *.7z
40 | *.csv
41 | *.dat
42 | *.dmg
43 | *.gz
44 | *.iso
45 | *.jar
46 | *.rar
47 | *.tar
48 | *.zip
49 | *.com
50 | *.class
51 | *.dll
52 | *.exe
53 | *.o
54 | *.seed
55 | *.so
56 | *.swo
57 | *.swp
58 | *.swn
59 | *.swm
60 | *.out
61 | *.pid
62 | *.lock
63 |
64 |
65 | ############################
66 | # Logs and databases
67 | ############################
68 |
69 | .tmp
70 | *.log
71 | *.sql
72 | *.sqlite
73 |
74 |
75 | ############################
76 | # Misc.
77 | ############################
78 |
79 | *#
80 | .idea
81 | nbproject
82 |
83 |
84 | ############################
85 | # Node.js
86 | ############################
87 |
88 | lib-cov
89 | lcov.info
90 | pids
91 | logs
92 | results
93 | build
94 | node_modules
95 | .node_history
96 | package-lock.json
97 | yarn.lock
98 |
99 | .env
100 | .txt
101 | public
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2022-present Alex Baker
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | 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
14 | SOFTWARE.
15 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Strapi Provider Upload IPFS Storage
2 |
3 |
4 |
5 | IPFS (Filebase, Pinata, Fleek, Web3, Lighthouse) provider for Strapi uploads.
6 |
7 | ## Installation
8 |
9 | ```bash
10 | # using yarn
11 | yarn add strapi-provider-upload-ipfs-storage
12 |
13 | # using npm
14 | npm install strapi-provider-upload-ipfs-storage --save
15 | ```
16 |
17 | ### Providers Configuration
18 |
19 | `./config/plugins.js`
20 |
21 | ```js
22 | module.exports = ({ env }) => ({
23 | // ...
24 | upload: {
25 | config: {
26 | provider: "strapi-provider-upload-ipfs-storage",
27 | providerOptions: {
28 | defaultStorage: "filebase",
29 | filebase: {
30 | // https://console.filebase.com/keys
31 | key: env("FILEBASE_KEY"),
32 | secret: env("FILEBASE_SECRET"),
33 | bucket: env("FILEBASE_BUCKET"),
34 | },
35 | pinata: {
36 | // https://app.pinata.cloud/keys
37 | jwt: env("PINATA_JWT"),
38 | },
39 | fleek: {
40 | // https://app.fleek.co/#/settings/general/profile
41 | key: env("FLEEK_KEY"),
42 | secret: env("FLEEK_SECRET"),
43 | bucket: env("FLEEK_BUCKET"),
44 | },
45 | web3: {
46 | // https://web3.storage/tokens/
47 | token: env("WEB3_TOKEN"),
48 | },
49 | lighthouse: {
50 | // https://files.lighthouse.storage/dashboard/apikey
51 | token: env("LIGHTHOUSE_TOKEN"),
52 | },
53 | },
54 | },
55 | },
56 | // ...
57 | });
58 | ```
59 |
60 | `.env`
61 |
62 | ```bash
63 | FILEBASE_KEY=""
64 | FILEBASE_SECRET=""
65 | FILEBASE_BUCKET=""
66 |
67 | PINATA_JWT=""
68 |
69 | FLEEK_KEY=""
70 | FLEEK_SECRET=""
71 | FLEEK_BUCKET=""
72 |
73 | WEB3_TOKEN=""
74 |
75 | LIGHTHOUSE_TOKEN=""
76 | ```
77 |
78 | ## Configuration Strapi + Filebase [ [tutorial](https://docs.filebase.com/configurations/third-party-configurations/backup-client-configurations/strapi-provider-plugin) ]
79 |
80 |
81 |
82 | | Variable | Type | Description | Required |
83 | | -------- | ------ | ---------------------- | -------- |
84 | | key | string | Filebase access key | yes |
85 | | secret | string | Filebase access secret | yes |
86 | | bucket | string | Filebase bucket name | yes |
87 |
88 | ```js
89 | module.exports = ({ env }) => ({
90 | // ...
91 | upload: {
92 | config: {
93 | provider: "strapi-provider-upload-ipfs-storage",
94 | providerOptions: {
95 | defaultStorage: "filebase",
96 | filebase: {
97 | // https://console.filebase.com/keys
98 | key: env("FILEBASE_KEY"),
99 | secret: env("FILEBASE_SECRET"),
100 | bucket: env("FILEBASE_BUCKET"),
101 | },
102 | },
103 | },
104 | },
105 | // ...
106 | });
107 | ```
108 |
109 | ## Configuration Strapi + Pinata
110 |
111 |
112 |
113 | | Variable | Type | Description | Required |
114 | | -------- | ------ | -------------------------------- | -------- |
115 | | jwt | string | Pinata JWT (Secret access token) | yes |
116 |
117 | ```js
118 | module.exports = ({ env }) => ({
119 | // ...
120 | upload: {
121 | config: {
122 | provider: "strapi-provider-upload-ipfs-storage",
123 | providerOptions: {
124 | defaultStorage: "pinata",
125 | pinata: {
126 | // https://app.pinata.cloud/keys
127 | jwt: env("PINATA_JWT"),
128 | },
129 | },
130 | },
131 | },
132 | // ...
133 | });
134 | ```
135 |
136 | ## Configuration Strapi + Fleek
137 |
138 |
139 |
140 | | Variable | Type | Description | Required |
141 | | -------- | ------ | -------------------------------------- | -------- |
142 | | key | string | Fleek Storage API key | yes |
143 | | secret | string | Fleek Storage API secret | yes |
144 | | bucket | string | Fleek bucket name (e.g. 71a...-bucket) | yes |
145 |
146 | ```js
147 | module.exports = ({ env }) => ({
148 | // ...
149 | upload: {
150 | config: {
151 | provider: "strapi-provider-upload-ipfs-storage",
152 | providerOptions: {
153 | defaultStorage: "fleek",
154 | fleek: {
155 | // https://app.fleek.co/#/settings/general/profile
156 | key: env("FLEEK_KEY"),
157 | secret: env("FLEEK_SECRET"),
158 | bucket: env("FLEEK_BUCKET"),
159 | },
160 | },
161 | },
162 | },
163 | // ...
164 | });
165 | ```
166 |
167 | ## Configuration Strapi + Web3
168 |
169 |
170 |
171 | | Variable | Type | Description | Required |
172 | | -------- | ------ | ---------------------- | -------- |
173 | | token | string | Web3 Storage API Token | yes |
174 |
175 | ```js
176 | module.exports = ({ env }) => ({
177 | // ...
178 | upload: {
179 | config: {
180 | provider: "strapi-provider-upload-ipfs-storage",
181 | providerOptions: {
182 | defaultStorage: "web3",
183 | web3: {
184 | // https://web3.storage/tokens/
185 | token: env("WEB3_TOKEN"),
186 | },
187 | },
188 | },
189 | },
190 | // ...
191 | });
192 | ```
193 |
194 | ## Configuration Strapi + Lighthouse
195 |
196 |
197 |
198 | | Variable | Type | Description | Required |
199 | | -------- | ------ | ---------------------------- | -------- |
200 | | token | string | Lighthouse Storage API Token | yes |
201 |
202 | ```js
203 | module.exports = ({ env }) => ({
204 | // ...
205 | upload: {
206 | config: {
207 | provider: "strapi-provider-upload-ipfs-storage",
208 | providerOptions: {
209 | defaultStorage: "lighthouse",
210 | lighthouse: {
211 | // https://files.lighthouse.storage/dashboard/apikey
212 | token: env("LIGHTHOUSE_TOKEN"),
213 | },
214 | },
215 | },
216 | },
217 | // ...
218 | });
219 | ```
220 |
221 | ### Security Middleware Configuration
222 |
223 | Due to the default settings in the Strapi Security Middleware you will need to modify the `contentSecurityPolicy` settings to properly see thumbnail previews in the Media Library. You should replace `strapi::security` string with the object bellow instead as explained in the [middleware configuration](https://docs.strapi.io/developer-docs/latest/setup-deployment-guides/configurations/required/middlewares.html#loading-order) documentation.
224 |
225 | `./config/middlewares.js`
226 |
227 | ```js
228 | module.exports = [
229 | // ...
230 | {
231 | name: "strapi::security",
232 | config: {
233 | contentSecurityPolicy: {
234 | useDefaults: true,
235 | directives: {
236 | "connect-src": ["'self'", "https:"],
237 | "img-src": [
238 | "'self'",
239 | "data:",
240 | "blob:",
241 | "dl.airtable.com",
242 | "*.ipfs.dweb.link", // ipfs.tech
243 | "*.ipfs.cf-ipfs.com", // cloudflare.com
244 | "*.ipfs.w3s.link", // web3.storage
245 | ],
246 | "media-src": [
247 | "'self'",
248 | "data:",
249 | "blob:",
250 | "dl.airtable.com",
251 | "*.ipfs.dweb.link", // ipfs.tech
252 | "*.ipfs.cf-ipfs.com", // cloudflare.com
253 | "*.ipfs.w3s.link", // web3.storage
254 | ],
255 | upgradeInsecureRequests: null,
256 | },
257 | },
258 | },
259 | },
260 | // ...
261 | ];
262 | ```
263 |
264 | ## Links
265 |
266 | - [Strapi website](https://strapi.io/)
267 | - [IPFS website](https://ipfs.tech/)
268 | - [Filebase website](https://filebase.com/)
269 | - [Pinata website](https://pinata.cloud/)
270 | - [Fleek website](https://fleek.co/)
271 | - [Web3 website](https://web3.storage/)
272 | - [Lighthouse website](https://lighthouse.storage/)
273 |
274 | ---
275 |
276 | `(c)` Alex Baker
277 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | /**
4 | * Module dependencies
5 | */
6 |
7 | /* eslint-disable no-unused-vars */
8 | // Public node modules.
9 | const ipfs = require("ipfs-storage");
10 |
11 | module.exports = {
12 | init(config) {
13 | return {
14 | uploadStream(file) {
15 | return new Promise(async (resolve, reject) => {
16 | try {
17 | const url = await ipfs.uploadFile[config.defaultStorage](
18 | config[config.defaultStorage],
19 | file
20 | );
21 | file.url = url;
22 | resolve();
23 | } catch (e) {
24 | reject(e);
25 | }
26 | });
27 | },
28 | upload(file) {
29 | return new Promise(async (resolve, reject) => {
30 | try {
31 | const url = await ipfs.uploadFile[config.defaultStorage](
32 | config[config.defaultStorage],
33 | file
34 | );
35 | file.url = url;
36 | resolve();
37 | } catch (e) {
38 | reject(e);
39 | }
40 | });
41 | },
42 | delete(file) {
43 | return new Promise(async (resolve, reject) => {
44 | try {
45 | await ipfs.deleteFile[config.defaultStorage](
46 | config[config.defaultStorage],
47 | file
48 | );
49 | resolve();
50 | } catch (e) {
51 | reject(e);
52 | }
53 | });
54 | },
55 | };
56 | },
57 | };
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "strapi-provider-upload-ipfs-storage",
3 | "version": "1.1.0",
4 | "description": "IPFS upload provider for Strapi",
5 | "keywords": [
6 | "upload",
7 | "ipfs",
8 | "web3",
9 | "filebase",
10 | "pinata",
11 | "fleek",
12 | "strapi",
13 | "lighthouse"
14 | ],
15 | "homepage": "https://github.com/alexbakers/strapi-provider-upload-ipfs-storage",
16 | "bugs": {
17 | "url": "https://github.com/alexbakers/strapi-provider-upload-ipfs-storage/issues"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git://github.com/alexbakers/strapi-provider-upload-ipfs-storage.git"
22 | },
23 | "license": "MIT",
24 | "main": "./lib/index.js",
25 | "directories": {
26 | "lib": "./lib"
27 | },
28 | "scripts": {
29 | "test": "node ./test/index.test.js"
30 | },
31 | "dependencies": {
32 | "ipfs-storage": "^1.2.1"
33 | },
34 | "peerDependencies": {
35 | "@strapi/strapi": "^4.5.1"
36 | },
37 | "engines": {
38 | "node": ">=14.19.1 <=18.x.x",
39 | "npm": ">=6.0.0"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/public/banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbakers/strapi-provider-upload-ipfs-storage/62f8570ad20693cbd24661868070b88fe6e3e8f4/public/banner.png
--------------------------------------------------------------------------------
/public/filebase-provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbakers/strapi-provider-upload-ipfs-storage/62f8570ad20693cbd24661868070b88fe6e3e8f4/public/filebase-provider.png
--------------------------------------------------------------------------------
/public/fleek-provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbakers/strapi-provider-upload-ipfs-storage/62f8570ad20693cbd24661868070b88fe6e3e8f4/public/fleek-provider.png
--------------------------------------------------------------------------------
/public/lighthouse-provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbakers/strapi-provider-upload-ipfs-storage/62f8570ad20693cbd24661868070b88fe6e3e8f4/public/lighthouse-provider.png
--------------------------------------------------------------------------------
/public/pinata-provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbakers/strapi-provider-upload-ipfs-storage/62f8570ad20693cbd24661868070b88fe6e3e8f4/public/pinata-provider.png
--------------------------------------------------------------------------------
/public/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbakers/strapi-provider-upload-ipfs-storage/62f8570ad20693cbd24661868070b88fe6e3e8f4/public/screenshot.png
--------------------------------------------------------------------------------
/public/web3-provider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/alexbakers/strapi-provider-upload-ipfs-storage/62f8570ad20693cbd24661868070b88fe6e3e8f4/public/web3-provider.png
--------------------------------------------------------------------------------
/test/index.test.js:
--------------------------------------------------------------------------------
1 | const fs = require("fs");
2 | const { join } = require("path");
3 | const ipfs = require("ipfs-storage");
4 |
5 | require("dotenv").config();
6 |
7 | fs.readFile(join(__dirname, "..", "banner.png"), async (err, data) => {
8 | if (err) {
9 | console.log("🆘 ERROR:", err);
10 | return;
11 | }
12 |
13 | if (
14 | !process.env.FILEBASE_KEY &&
15 | !process.env.PINATA_JWT &&
16 | !process.env.FLEEK_KEY &&
17 | !process.env.WEB3_TOKEN &&
18 | !process.env.LIGHTHOUSE_TOKEN
19 | ) {
20 | console.log("🆘 ERROR:", "Create .env file");
21 | return;
22 | }
23 |
24 | try {
25 | const url = await ipfs.uploadFile.filebase(
26 | {
27 | key: process.env.FILEBASE_KEY,
28 | secret: process.env.FILEBASE_SECRET,
29 | bucket: process.env.FILEBASE_BUCKET,
30 | },
31 | {
32 | hash: "banner",
33 | ext: ".png",
34 | buffer: data,
35 | }
36 | );
37 | console.log("✅ FILEBASE:", url);
38 | await ipfs.deleteFile.filebase(
39 | {
40 | key: process.env.FILEBASE_KEY,
41 | secret: process.env.FILEBASE_SECRET,
42 | bucket: process.env.FILEBASE_BUCKET,
43 | },
44 | {
45 | hash: "banner",
46 | ext: ".png",
47 | }
48 | );
49 | } catch (err) {
50 | console.log("🆘 FILEBASE:", err);
51 | }
52 |
53 | try {
54 | const url = await ipfs.uploadFile.pinata(
55 | {
56 | jwt: process.env.PINATA_JWT,
57 | },
58 | {
59 | hash: "banner",
60 | ext: ".png",
61 | buffer: data,
62 | }
63 | );
64 | console.log("✅ PINATA:", url);
65 | await ipfs.deleteFile.pinata(
66 | {
67 | jwt: process.env.PINATA_JWT,
68 | },
69 | {
70 | url,
71 | }
72 | );
73 | } catch (err) {
74 | console.log("🆘 PINATA:", err);
75 | }
76 |
77 | try {
78 | const url = await ipfs.uploadFile.fleek(
79 | {
80 | key: process.env.FLEEK_KEY,
81 | secret: process.env.FLEEK_SECRET,
82 | bucket: process.env.FLEEK_BUCKET,
83 | },
84 | {
85 | hash: "banner",
86 | ext: ".png",
87 | buffer: data,
88 | }
89 | );
90 | console.log("✅ FLEEK:", url);
91 | await ipfs.deleteFile.fleek(
92 | {
93 | key: process.env.FLEEK_KEY,
94 | secret: process.env.FLEEK_SECRET,
95 | bucket: process.env.FLEEK_BUCKET,
96 | },
97 | {
98 | hash: "banner",
99 | ext: ".png",
100 | }
101 | );
102 | } catch (err) {
103 | console.log("🆘 FLEEK:", err);
104 | }
105 |
106 | try {
107 | const url = await ipfs.uploadFile.web3(
108 | {
109 | token: process.env.WEB3_TOKEN,
110 | },
111 | {
112 | hash: "banner",
113 | ext: ".png",
114 | buffer: data,
115 | }
116 | );
117 | console.log("✅ WEB3:", url);
118 | await ipfs.deleteFile.web3(
119 | {
120 | token: process.env.WEB3_TOKEN,
121 | },
122 | {
123 | url,
124 | }
125 | );
126 | } catch (err) {
127 | console.log("🆘 WEB3:", err);
128 | }
129 |
130 | try {
131 | const url = await ipfs.uploadFile.lighthouse(
132 | {
133 | token: process.env.LIGHTHOUSE_TOKEN,
134 | },
135 | {
136 | hash: "banner",
137 | ext: ".png",
138 | buffer: data,
139 | }
140 | );
141 | console.log("✅ LIGHTHOUSE:", url);
142 | await ipfs.deleteFile.lighthouse(
143 | {
144 | token: process.env.LIGHTHOUSE_TOKEN,
145 | },
146 | {
147 | url,
148 | }
149 | );
150 | } catch (err) {
151 | console.log("🆘 LIGHTHOUSE:", err);
152 | }
153 | });
154 |
--------------------------------------------------------------------------------