Skip to content

Commit 7d9453b

Browse files
authored
add signature for encrypt handlers (#1189)
* add signature for encrypt handlers
1 parent 012acae commit 7d9453b

10 files changed

Lines changed: 294 additions & 17 deletions

File tree

docs/API.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,15 @@ returns amount of tokens to transfer to the provider account
203203

204204
returns encrypted blob
205205

206-
#### Request
206+
#### Query Parameters
207+
208+
| name | type | required | description |
209+
| --------------- | ------ | -------- | ------------------------------------------------------- |
210+
| nonce | string | v | is required to verify a request paired with a signature |
211+
| consumerAddress | string | v | consumer address |
212+
| signature | string | v | signed message based on ` nonce` |
213+
214+
#### Request body
207215

208216
```
209217
string
@@ -217,6 +225,44 @@ string
217225

218226
---
219227

228+
## EncryptFile
229+
230+
### `HTTP` POST /api/services/encryptFile
231+
232+
#### Description
233+
234+
returns encrypted file
235+
236+
#### Query Parameters
237+
238+
| name | type | required | description |
239+
| --------------- | ------ | -------- | ------------------------------------------------------- |
240+
| nonce | string | v | is required to verify a request paired with a signature |
241+
| consumerAddress | string | v | consumer address |
242+
| signature | string | v | signed message based on ` nonce` |
243+
244+
#### Request body
245+
246+
if Content-Type = 'application/json'
247+
248+
```
249+
BaseFileObject
250+
```
251+
252+
if Content-Type = 'application/octet-stream' || 'multipart/form-data'
253+
254+
```
255+
FileContent(bytes)
256+
```
257+
258+
#### Response
259+
260+
```
261+
0x123
262+
```
263+
264+
---
265+
220266
## Decrypt DDO
221267

222268
### `HTTP` POST /api/services/decrypt

docs/PolicyServer.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ Called whenever a new encrypt command is received by Ocean Node
9595
}
9696
```
9797

98+
### encryptFile
99+
100+
Called whenever a new encryptFile command is received by Ocean Node
101+
102+
```json
103+
{
104+
"action": "encrypt",
105+
"policyServer": {},
106+
"file"?: object
107+
}
108+
```
109+
98110
### decrypt
99111

100112
Called whenever a new decrypt command is received by Ocean Node

src/@types/commands.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,23 @@ export interface DecryptDDOCommand extends Command {
120120
}
121121

122122
export interface EncryptCommand extends Command {
123+
nonce: string
124+
consumerAddress: string
125+
signature: string
123126
blob: string
124127
encoding?: string
125128
encryptionType?: EncryptMethod.AES | EncryptMethod.ECIES
129+
policyServer?: any // object to pass to policy server
126130
}
127131

128132
export interface EncryptFileCommand extends Command {
133+
nonce: string
134+
consumerAddress: string
135+
signature: string
129136
encryptionType?: EncryptMethod.AES | EncryptMethod.ECIES
130137
files?: BaseFileObject
131138
rawData?: Buffer
132-
// UrlFileObject | ArweaveFileObject | IpfsFileObject
139+
policyServer?: any // object to pass to policy server
133140
}
134141

135142
export interface NonceCommand extends Command {

src/components/core/handler/encryptHandler.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ import { EncryptCommand, EncryptFileCommand } from '../../../@types/commands.js'
44
import * as base58 from 'base58-js'
55
import { Readable } from 'stream'
66
import { Storage } from '../../storage/index.js'
7-
import { getConfiguration } from '../../../utils/index.js'
7+
import { getConfiguration, isPolicyServerConfigured } from '../../../utils/index.js'
8+
import { PolicyServer } from '../../policyServer/index.js'
89
import { EncryptMethod } from '../../../@types/fileObject.js'
910
import {
1011
ValidateParams,
@@ -49,9 +50,41 @@ export class EncryptHandler extends CommandHandler {
4950

5051
async handle(task: EncryptCommand): Promise<P2PCommandResponse> {
5152
const validationResponse = await this.verifyParamsAndRateLimits(task)
53+
5254
if (this.shouldDenyTaskHandling(validationResponse)) {
5355
return validationResponse
5456
}
57+
const isAuthRequestValid = await this.validateTokenOrSignature(
58+
task.authorization,
59+
task.consumerAddress,
60+
task.nonce,
61+
task.signature,
62+
String(task.nonce)
63+
)
64+
if (isAuthRequestValid.status.httpStatus !== 200) {
65+
return isAuthRequestValid
66+
}
67+
68+
if (isPolicyServerConfigured()) {
69+
const policyServer = new PolicyServer()
70+
const response = await policyServer.checkEncrypt(
71+
task.consumerAddress,
72+
task.policyServer
73+
)
74+
if (!response) {
75+
CORE_LOGGER.logMessage(
76+
`Error: Encrypt for ${task.consumerAddress} was denied`,
77+
true
78+
)
79+
return {
80+
stream: null,
81+
status: {
82+
httpStatus: 403,
83+
error: `Error: Encrypt for ${task.consumerAddress} was denied`
84+
}
85+
}
86+
}
87+
}
5588
try {
5689
const oceanNode = this.getOceanNode()
5790
// prepare an empty array in case if
@@ -112,6 +145,39 @@ export class EncryptFileHandler extends CommandHandler {
112145
if (this.shouldDenyTaskHandling(validationResponse)) {
113146
return validationResponse
114147
}
148+
const isAuthRequestValid = await this.validateTokenOrSignature(
149+
task.authorization,
150+
task.consumerAddress,
151+
task.nonce,
152+
task.signature,
153+
String(task.nonce)
154+
)
155+
if (isAuthRequestValid.status.httpStatus !== 200) {
156+
return isAuthRequestValid
157+
}
158+
159+
if (isPolicyServerConfigured()) {
160+
const policyServer = new PolicyServer()
161+
const response = await policyServer.checkEncryptFile(
162+
task.consumerAddress,
163+
task.policyServer,
164+
task.files
165+
)
166+
if (!response) {
167+
CORE_LOGGER.logMessage(
168+
`Error: EncryptFile for ${task.consumerAddress} was denied`,
169+
true
170+
)
171+
return {
172+
stream: null,
173+
status: {
174+
httpStatus: 403,
175+
error: `Error: EncryptFile for ${task.consumerAddress} was denied`
176+
}
177+
}
178+
}
179+
}
180+
115181
try {
116182
const oceanNode = this.getOceanNode()
117183
const config = await getConfiguration()

src/components/core/handler/handler.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,12 @@ export abstract class CommandHandler
182182
): Promise<P2PCommandResponse> {
183183
const oceanNode = this.getOceanNode()
184184
const auth = oceanNode.getAuth()
185+
if (!auth) {
186+
return {
187+
stream: null,
188+
status: { httpStatus: 401, error: 'Auth not configured' }
189+
}
190+
}
185191
const isAuthRequestValid = await auth.validateAuthenticationOrToken({
186192
token: authToken,
187193
address,

src/components/httpRoutes/provider.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ providerRoutes.post(`${SERVICES_API_BASE_PATH}/encrypt`, async (req, res) => {
4848
encoding: 'string',
4949
encryptionType: EncryptMethod.ECIES,
5050
command: PROTOCOL_COMMANDS.ENCRYPT,
51-
caller: req.caller
51+
caller: req.caller,
52+
nonce: req.query.nonce as string,
53+
consumerAddress: req.query.consumerAddress as string,
54+
signature: req.query.signature as string
5255
})
5356
if (result.stream) {
5457
const encryptedData = await streamToString(result.stream as Readable)
@@ -100,7 +103,10 @@ providerRoutes.post(`${SERVICES_API_BASE_PATH}/encryptFile`, async (req, res) =>
100103
rawData: input,
101104
encryptionType: encryptMethod,
102105
command: PROTOCOL_COMMANDS.ENCRYPT_FILE,
103-
caller: req.caller
106+
caller: req.caller,
107+
nonce: req.query.nonce as string,
108+
consumerAddress: req.query.consumerAddress as string,
109+
signature: req.query.signature as string
104110
})
105111
return result
106112
}
@@ -116,7 +122,10 @@ providerRoutes.post(`${SERVICES_API_BASE_PATH}/encryptFile`, async (req, res) =>
116122
files: req.body as BaseFileObject,
117123
encryptionType: encryptMethod,
118124
command: PROTOCOL_COMMANDS.ENCRYPT_FILE,
119-
caller: req.caller
125+
caller: req.caller,
126+
nonce: req.query.nonce as string,
127+
consumerAddress: req.query.consumerAddress as string,
128+
signature: req.query.signature as string
120129
})
121130
return await writeResponse(result, encryptMethod)
122131
// raw data on body

src/components/policyServer/index.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { DDO } from '@oceanprotocol/ddo-js'
22
import { PolicyServerResult } from '../../@types/policyServer.js'
33
import { isDefined } from '../../utils/util.js'
4+
import { BaseFileObject } from '../../@types/fileObject.js'
45

56
export class PolicyServer {
67
serverUrl: string
@@ -69,6 +70,32 @@ export class PolicyServer {
6970
return await this.askServer(command)
7071
}
7172

73+
async checkEncrypt(
74+
consumerAddress: string,
75+
policyServer: any
76+
): Promise<PolicyServerResult> {
77+
const command = {
78+
action: 'encrypt',
79+
consumerAddress,
80+
policyServer
81+
}
82+
return await this.askServer(command)
83+
}
84+
85+
async checkEncryptFile(
86+
consumerAddress: string,
87+
policyServer: any,
88+
files?: BaseFileObject
89+
): Promise<PolicyServerResult> {
90+
const command = {
91+
action: 'encryptFile',
92+
consumerAddress,
93+
policyServer,
94+
files
95+
}
96+
return await this.askServer(command)
97+
}
98+
7299
async checkDownload(
73100
documentId: string,
74101
ddo: DDO,

0 commit comments

Comments
 (0)