@iexec/web3mail 0.3.0 → 0.4.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/dist/config/config.d.ts +2 -0
- package/dist/config/config.js +2 -0
- package/dist/utils/ipfs-service.d.ts +7 -0
- package/dist/utils/ipfs-service.js +28 -0
- package/dist/utils/validators.js +2 -2
- package/dist/web3mail/sendEmail.js +17 -3
- package/package.json +3 -2
- package/src/config/config.ts +2 -0
- package/src/utils/ipfs-service.ts +22 -0
- package/src/utils/validators.ts +2 -2
- package/src/web3mail/sendEmail.ts +21 -3
package/dist/config/config.d.ts
CHANGED
|
@@ -4,3 +4,5 @@ export declare const DATAPROTECTOR_SUBGRAPH_ENDPOINT = "https://thegraph-product
|
|
|
4
4
|
export declare const MAX_DESIRED_APP_ORDER_PRICE = 0;
|
|
5
5
|
export declare const MAX_DESIRED_WORKERPOOL_ORDER_PRICE = 0;
|
|
6
6
|
export declare const DEFAULT_CONTENT_TYPE = "text/plain";
|
|
7
|
+
export declare const IPFS_UPLOAD_URL = "/dns4/ipfs-upload.v8-bellecour.iex.ec/https";
|
|
8
|
+
export declare const DEFAULT_IPFS_GATEWAY = "https://ipfs-gateway.v8-bellecour.iex.ec";
|
package/dist/config/config.js
CHANGED
|
@@ -4,3 +4,5 @@ export const DATAPROTECTOR_SUBGRAPH_ENDPOINT = 'https://thegraph-product.iex.ec/
|
|
|
4
4
|
export const MAX_DESIRED_APP_ORDER_PRICE = 0;
|
|
5
5
|
export const MAX_DESIRED_WORKERPOOL_ORDER_PRICE = 0;
|
|
6
6
|
export const DEFAULT_CONTENT_TYPE = 'text/plain';
|
|
7
|
+
export const IPFS_UPLOAD_URL = '/dns4/ipfs-upload.v8-bellecour.iex.ec/https';
|
|
8
|
+
export const DEFAULT_IPFS_GATEWAY = 'https://ipfs-gateway.v8-bellecour.iex.ec';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { create } from 'kubo-rpc-client';
|
|
11
|
+
import { DEFAULT_IPFS_GATEWAY, IPFS_UPLOAD_URL } from './../config/config.js';
|
|
12
|
+
const get = (cid, { ipfsGateway = DEFAULT_IPFS_GATEWAY } = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
13
|
+
const multiaddr = `/ipfs/${cid.toString()}`;
|
|
14
|
+
const publicUrl = `${ipfsGateway}${multiaddr}`;
|
|
15
|
+
const res = yield fetch(publicUrl);
|
|
16
|
+
if (!res.ok) {
|
|
17
|
+
throw Error(`Failed to load content from ${publicUrl}`);
|
|
18
|
+
}
|
|
19
|
+
const arrayBuffer = yield res.arrayBuffer();
|
|
20
|
+
return new Uint8Array(arrayBuffer);
|
|
21
|
+
});
|
|
22
|
+
const add = (content, { ipfsGateway = DEFAULT_IPFS_GATEWAY } = {}) => __awaiter(void 0, void 0, void 0, function* () {
|
|
23
|
+
const ipfsClient = create(IPFS_UPLOAD_URL);
|
|
24
|
+
const { cid } = yield ipfsClient.add(content);
|
|
25
|
+
yield get(cid.toString(), { ipfsGateway });
|
|
26
|
+
return cid.toString();
|
|
27
|
+
});
|
|
28
|
+
export { add, get };
|
package/dist/utils/validators.js
CHANGED
|
@@ -12,8 +12,8 @@ export const addressOrEnsSchema = () => string()
|
|
|
12
12
|
.test('is-address-or-ens', '${path} should be an ethereum address or a ENS name', (value) => isUndefined(value) || isAddressTest(value) || isEnsTest(value));
|
|
13
13
|
// 78 char length for email subject (rfc2822)
|
|
14
14
|
export const emailSubjectSchema = () => string().max(78).strict();
|
|
15
|
-
//
|
|
16
|
-
export const emailContentSchema = () => string().max(
|
|
15
|
+
// Limit of 512,000 bytes (512 kilo-bytes)
|
|
16
|
+
export const emailContentSchema = () => string().max(512000);
|
|
17
17
|
// Valid content types for the variable 'contentType'
|
|
18
18
|
const validContentTypes = ['text/plain', 'text/html'];
|
|
19
19
|
export const contentTypeSchema = () => string().oneOf(validContentTypes, 'Invalid contentType').optional();
|
|
@@ -12,6 +12,7 @@ import { WorkflowError } from '../utils/errors.js';
|
|
|
12
12
|
import { generateSecureUniqueId } from '../utils/generateUniqueId.js';
|
|
13
13
|
import { checkProtectedDataValidity } from '../utils/subgraphQuery.js';
|
|
14
14
|
import { addressOrEnsSchema, contentTypeSchema, emailContentSchema, emailSubjectSchema, senderNameSchema, throwIfMissing, } from '../utils/validators.js';
|
|
15
|
+
import * as ipfs from './../utils/ipfs-service.js';
|
|
15
16
|
export const sendEmail = ({ graphQLClient = throwIfMissing(), iexec = throwIfMissing(), emailSubject, emailContent, contentType = DEFAULT_CONTENT_TYPE, senderName, protectedData, }) => __awaiter(void 0, void 0, void 0, function* () {
|
|
16
17
|
var _a, _b, _c, _d, _e;
|
|
17
18
|
try {
|
|
@@ -94,9 +95,22 @@ export const sendEmail = ({ graphQLClient = throwIfMissing(), iexec = throwIfMis
|
|
|
94
95
|
const emailContentId = generateSecureUniqueId(16);
|
|
95
96
|
const optionsId = generateSecureUniqueId(16);
|
|
96
97
|
yield iexec.secrets.pushRequesterSecret(emailSubjectId, vEmailSubject);
|
|
97
|
-
|
|
98
|
-
yield iexec.
|
|
99
|
-
|
|
98
|
+
const emailContentEncryptionKey = iexec.dataset.generateEncryptionKey();
|
|
99
|
+
const encryptedFile = yield iexec.dataset
|
|
100
|
+
.encrypt(Buffer.from(vEmailContent, 'utf8'), emailContentEncryptionKey)
|
|
101
|
+
.catch((e) => {
|
|
102
|
+
throw new WorkflowError('Failed to encrypt email content', e);
|
|
103
|
+
});
|
|
104
|
+
const cid = yield ipfs.add(encryptedFile).catch((e) => {
|
|
105
|
+
throw new WorkflowError('Failed to upload encrypted email content', e);
|
|
106
|
+
});
|
|
107
|
+
const multiaddr = `/ipfs/${cid}`;
|
|
108
|
+
yield iexec.secrets.pushRequesterSecret(emailContentId, multiaddr);
|
|
109
|
+
yield iexec.secrets.pushRequesterSecret(optionsId, JSON.stringify({
|
|
110
|
+
contentType: vContentType,
|
|
111
|
+
senderName: vSenderName,
|
|
112
|
+
emailContentEncryptionKey,
|
|
113
|
+
}));
|
|
100
114
|
const requestorderToSign = yield iexec.order.createRequestorder({
|
|
101
115
|
app: WEB3_MAIL_DAPP_ADDRESS,
|
|
102
116
|
category: desiredPriceWorkerpoolOrder.category,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iexec/web3mail",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "This product enables users to confidentially store data–such as mail address, documents, personal information ...",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"homepage": "https://github.com/iExecBlockchainComputing/web3mail-sdk#readme",
|
|
40
40
|
"devDependencies": {
|
|
41
41
|
"@iexec/dataprotector": "^0.1.0",
|
|
42
|
-
"@types/jest": "^29.5.
|
|
42
|
+
"@types/jest": "^29.5.4",
|
|
43
43
|
"@typescript-eslint/eslint-plugin": "^5.54.0",
|
|
44
44
|
"eslint": "^8.35.0",
|
|
45
45
|
"eslint-config-prettier": "^8.6.0",
|
|
@@ -58,6 +58,7 @@
|
|
|
58
58
|
"@ethersproject/random": "^5.7.0",
|
|
59
59
|
"graphql-request": "^6.1.0",
|
|
60
60
|
"iexec": "^8.2.1",
|
|
61
|
+
"kubo-rpc-client": "^3.0.1",
|
|
61
62
|
"yup": "^1.1.1"
|
|
62
63
|
}
|
|
63
64
|
}
|
package/src/config/config.ts
CHANGED
|
@@ -5,3 +5,5 @@ export const DATAPROTECTOR_SUBGRAPH_ENDPOINT =
|
|
|
5
5
|
export const MAX_DESIRED_APP_ORDER_PRICE = 0;
|
|
6
6
|
export const MAX_DESIRED_WORKERPOOL_ORDER_PRICE = 0;
|
|
7
7
|
export const DEFAULT_CONTENT_TYPE = 'text/plain';
|
|
8
|
+
export const IPFS_UPLOAD_URL = '/dns4/ipfs-upload.v8-bellecour.iex.ec/https';
|
|
9
|
+
export const DEFAULT_IPFS_GATEWAY = 'https://ipfs-gateway.v8-bellecour.iex.ec';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { create } from 'kubo-rpc-client';
|
|
2
|
+
import { DEFAULT_IPFS_GATEWAY, IPFS_UPLOAD_URL } from './../config/config.js';
|
|
3
|
+
|
|
4
|
+
const get = async (cid, { ipfsGateway = DEFAULT_IPFS_GATEWAY } = {}) => {
|
|
5
|
+
const multiaddr = `/ipfs/${cid.toString()}`;
|
|
6
|
+
const publicUrl = `${ipfsGateway}${multiaddr}`;
|
|
7
|
+
const res = await fetch(publicUrl);
|
|
8
|
+
if (!res.ok) {
|
|
9
|
+
throw Error(`Failed to load content from ${publicUrl}`);
|
|
10
|
+
}
|
|
11
|
+
const arrayBuffer = await res.arrayBuffer();
|
|
12
|
+
return new Uint8Array(arrayBuffer);
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const add = async (content, { ipfsGateway = DEFAULT_IPFS_GATEWAY } = {}) => {
|
|
16
|
+
const ipfsClient = create(IPFS_UPLOAD_URL);
|
|
17
|
+
const { cid } = await ipfsClient.add(content);
|
|
18
|
+
await get(cid.toString(), { ipfsGateway });
|
|
19
|
+
return cid.toString();
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export { add, get };
|
package/src/utils/validators.ts
CHANGED
|
@@ -23,8 +23,8 @@ export const addressOrEnsSchema = () =>
|
|
|
23
23
|
// 78 char length for email subject (rfc2822)
|
|
24
24
|
export const emailSubjectSchema = () => string().max(78).strict();
|
|
25
25
|
|
|
26
|
-
//
|
|
27
|
-
export const emailContentSchema = () => string().max(
|
|
26
|
+
// Limit of 512,000 bytes (512 kilo-bytes)
|
|
27
|
+
export const emailContentSchema = () => string().max(512000);
|
|
28
28
|
|
|
29
29
|
// Valid content types for the variable 'contentType'
|
|
30
30
|
const validContentTypes = ['text/plain', 'text/html'];
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
SendEmailResponse,
|
|
23
23
|
SubgraphConsumer,
|
|
24
24
|
} from './types.js';
|
|
25
|
+
import * as ipfs from './../utils/ipfs-service.js';
|
|
25
26
|
|
|
26
27
|
export const sendEmail = async ({
|
|
27
28
|
graphQLClient = throwIfMissing(),
|
|
@@ -141,13 +142,30 @@ export const sendEmail = async ({
|
|
|
141
142
|
const emailSubjectId = generateSecureUniqueId(16);
|
|
142
143
|
const emailContentId = generateSecureUniqueId(16);
|
|
143
144
|
const optionsId = generateSecureUniqueId(16);
|
|
145
|
+
|
|
144
146
|
await iexec.secrets.pushRequesterSecret(emailSubjectId, vEmailSubject);
|
|
145
|
-
|
|
147
|
+
|
|
148
|
+
const emailContentEncryptionKey = iexec.dataset.generateEncryptionKey();
|
|
149
|
+
const encryptedFile = await iexec.dataset
|
|
150
|
+
.encrypt(Buffer.from(vEmailContent, 'utf8'), emailContentEncryptionKey)
|
|
151
|
+
.catch((e) => {
|
|
152
|
+
throw new WorkflowError('Failed to encrypt email content', e);
|
|
153
|
+
});
|
|
154
|
+
const cid = await ipfs.add(encryptedFile).catch((e) => {
|
|
155
|
+
throw new WorkflowError('Failed to upload encrypted email content', e);
|
|
156
|
+
});
|
|
157
|
+
const multiaddr = `/ipfs/${cid}`;
|
|
158
|
+
|
|
159
|
+
await iexec.secrets.pushRequesterSecret(emailContentId, multiaddr);
|
|
146
160
|
await iexec.secrets.pushRequesterSecret(
|
|
147
161
|
optionsId,
|
|
148
|
-
JSON.stringify({
|
|
162
|
+
JSON.stringify({
|
|
163
|
+
contentType: vContentType,
|
|
164
|
+
senderName: vSenderName,
|
|
165
|
+
emailContentEncryptionKey,
|
|
166
|
+
})
|
|
149
167
|
);
|
|
150
|
-
|
|
168
|
+
|
|
151
169
|
const requestorderToSign = await iexec.order.createRequestorder({
|
|
152
170
|
app: WEB3_MAIL_DAPP_ADDRESS,
|
|
153
171
|
category: desiredPriceWorkerpoolOrder.category,
|