-
Notifications
You must be signed in to change notification settings - Fork 186
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(http): create http frontend client
- Create HTTP client based on old services - Create HTTP client request interceptor: request - Create HTTP client generic: GenericRequest - Create HTTP client server: WzRequest, ApiCheck and WzAuthentication - Enhance server API backend client See #6995 - Rename ILogger type to Logger
- Loading branch information
Showing
16 changed files
with
1,157 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
# HTTPClient | ||
|
||
The `HTTPClient` provides a custom mechanim to do an API request to the backend side. | ||
|
||
This defines a request interceptor that disables the requests when `core.http` returns a response with status code 401, avoiding a problem in the login flow (with SAML). | ||
|
||
The request interceptor is used in the clients: | ||
|
||
- generic | ||
- server | ||
|
||
## Generic | ||
|
||
This client provides a method to run the request that injects some properties related to an index pattern and selected server API host in the headers of the API request that could be used for some backend endpoints | ||
|
||
### Usage | ||
|
||
#### Request | ||
|
||
```ts | ||
plugins.wazuhCore.http.request('GET', '/api/check-api', {}); | ||
``` | ||
|
||
## Server | ||
|
||
This client provides: | ||
|
||
- some methods to communicate with the Wazuh server API | ||
- manage authentication with Wazuh server API | ||
- store the login data | ||
|
||
### Usage | ||
|
||
#### Authentication | ||
|
||
```ts | ||
plugins.wazuhCore.http.auth(); | ||
``` | ||
|
||
#### Unauthentication | ||
|
||
```ts | ||
plugins.wazuhCore.http.unauth(); | ||
``` | ||
|
||
#### Request | ||
|
||
```ts | ||
plugins.wazuhCore.http.request('GET', '/agents', {}); | ||
``` | ||
|
||
#### CSV | ||
|
||
```ts | ||
plugins.wazuhCore.http.csv('GET', '/agents', {}); | ||
``` | ||
|
||
#### Check API id | ||
|
||
```ts | ||
plugins.wazuhCore.http.checkApiById('api-host-id'); | ||
``` | ||
|
||
#### Check API | ||
|
||
```ts | ||
plugins.wazuhCore.http.checkApi(apiHostData); | ||
``` | ||
|
||
#### Get user data | ||
|
||
```ts | ||
plugins.wazuhCore.http.getUserData(); | ||
``` | ||
|
||
The changes in the user data can be retrieved thourgh the `userData$` observable. | ||
|
||
```ts | ||
plugins.wazuhCore.http.userData$.subscribe(userData => { | ||
// do something with the data | ||
}); | ||
``` | ||
|
||
### Register interceptor | ||
|
||
In each application when this is mounted through the `mount` method, the request interceptor must be registered and when the application is unmounted must be unregistered. | ||
|
||
> We should research about the possibility to register/unregister the interceptor once in the `wazuh-core` plugin instead of registering/unregisting in each mount of application. | ||
```ts | ||
// setup lifecycle plugin method | ||
|
||
// Register an application | ||
core.application.register({ | ||
// rest of registration properties | ||
mount: () => { | ||
// Register the interceptor | ||
plugins.wazuhCore.http.register(); | ||
return () => { | ||
// Unregister the interceptor | ||
plugins.wazuhCore.http.unregister(); | ||
}; | ||
}, | ||
}); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export const PLUGIN_PLATFORM_REQUEST_HEADERS = { | ||
'osd-xsrf': 'kibana', | ||
}; | ||
|
||
export const HTTP_CLIENT_DEFAULT_TIMEOUT = 20000; |
127 changes: 127 additions & 0 deletions
127
plugins/wazuh-core/public/services/http/generic-client.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import { PLUGIN_PLATFORM_REQUEST_HEADERS } from './constants'; | ||
import { Logger } from '../../../common/services/configuration'; | ||
import { | ||
HTTPClientGeneric, | ||
HTTPClientRequestInterceptor, | ||
HTTPVerb, | ||
} from './types'; | ||
|
||
interface GenericRequestServices { | ||
request: HTTPClientRequestInterceptor['request']; | ||
getURL(path: string): string; | ||
getTimeout(): Promise<number>; | ||
getIndexPatternTitle(): Promise<string>; | ||
getServerAPI(): string; | ||
checkAPIById(apiId: string): Promise<any>; | ||
} | ||
|
||
export class GenericRequest implements HTTPClientGeneric { | ||
onErrorInterceptor?: (error: any) => Promise<void>; | ||
constructor( | ||
private logger: Logger, | ||
private services: GenericRequestServices, | ||
) {} | ||
async request( | ||
method: HTTPVerb, | ||
path: string, | ||
payload = null, | ||
returnError = false, | ||
) { | ||
try { | ||
if (!method || !path) { | ||
throw new Error('Missing parameters'); | ||
} | ||
const timeout = await this.services.getTimeout(); | ||
const requestHeaders = { | ||
...PLUGIN_PLATFORM_REQUEST_HEADERS, | ||
'content-type': 'application/json', | ||
}; | ||
const url = this.services.getURL(path); | ||
|
||
try { | ||
requestHeaders.pattern = await this.services.getIndexPatternTitle(); | ||
} catch (error) {} | ||
|
||
try { | ||
requestHeaders.id = this.services.getServerAPI(); | ||
} catch (error) { | ||
// Intended | ||
} | ||
var options = {}; | ||
|
||
if (method === 'GET') { | ||
options = { | ||
method: method, | ||
headers: requestHeaders, | ||
url: url, | ||
timeout: timeout, | ||
}; | ||
} | ||
if (method === 'PUT') { | ||
options = { | ||
method: method, | ||
headers: requestHeaders, | ||
data: payload, | ||
url: url, | ||
timeout: timeout, | ||
}; | ||
} | ||
if (method === 'POST') { | ||
options = { | ||
method: method, | ||
headers: requestHeaders, | ||
data: payload, | ||
url: url, | ||
timeout: timeout, | ||
}; | ||
} | ||
if (method === 'DELETE') { | ||
options = { | ||
method: method, | ||
headers: requestHeaders, | ||
data: payload, | ||
url: url, | ||
timeout: timeout, | ||
}; | ||
} | ||
|
||
const data = await this.services.request(options); | ||
if (!data) { | ||
throw new Error(`Error doing a request to ${url}, method: ${method}.`); | ||
} | ||
|
||
return data; | ||
} catch (error) { | ||
//if the requests fails, we need to check if the API is down | ||
const currentApi = this.services.getServerAPI(); //JSON.parse(AppState.getCurrentAPI() || '{}'); | ||
if (currentApi) { | ||
try { | ||
await this.services.checkAPIById(currentApi); | ||
} catch (err) { | ||
// const wzMisc = new WzMisc(); | ||
// wzMisc.setApiIsDown(true); | ||
// if ( | ||
// ['/settings', '/health-check', '/blank-screen'].every( | ||
// pathname => | ||
// !NavigationService.getInstance() | ||
// .getPathname() | ||
// .startsWith(pathname), | ||
// ) | ||
// ) { | ||
// NavigationService.getInstance().navigate('/health-check'); | ||
// } | ||
} | ||
} | ||
// if(this.onErrorInterceptor){ | ||
// await this.onErrorInterceptor(error) | ||
// } | ||
if (returnError) return Promise.reject(error); | ||
return (((error || {}).response || {}).data || {}).message || false | ||
? Promise.reject(new Error(error.response.data.message)) | ||
: Promise.reject(error || new Error('Server did not respond')); | ||
} | ||
} | ||
setOnErrorInterceptor(onErrorInterceptor: (error: any) => Promise<void>) { | ||
this.onErrorInterceptor = onErrorInterceptor; | ||
} | ||
} |
Oops, something went wrong.