diff --git a/.generator/schemas/v2/openapi.yaml b/.generator/schemas/v2/openapi.yaml index 4bc99f94bc1d..347c49b18c0e 100644 --- a/.generator/schemas/v2/openapi.yaml +++ b/.generator/schemas/v2/openapi.yaml @@ -83901,6 +83901,89 @@ components: type: string x-enum-varnames: - USERS + StegadographyGetWidgetsRequest: + description: Multipart form data containing the PNG image to scan for watermarks. + properties: + image: + description: PNG image file to scan for embedded watermarks. + example: "screenshot.png" + format: binary + type: string + required: + - image + type: object + StegadographyGetWidgetsResponse: + description: Response containing watermarked widgets recovered from an image. + properties: + data: + $ref: "#/components/schemas/StegadographyWidgetItems" + required: + - data + type: object + StegadographyWidget: + description: A single watermarked widget resource recovered from an image. + properties: + attributes: + $ref: "#/components/schemas/StegadographyWidgetAttributes" + id: + description: Composite identifier formed from the organization ID and watermark, separated by a colon. + example: "abc123:0123456789abcdef" + type: string + type: + $ref: "#/components/schemas/StegadographyWidgetType" + required: + - id + - type + - attributes + type: object + StegadographyWidgetAttributes: + description: Attributes of a watermarked widget recovered from an image. + properties: + locationx: + description: Horizontal pixel coordinate where the watermark was found in the image. + example: 100 + format: int64 + type: integer + locationy: + description: Vertical pixel coordinate where the watermark was found in the image. + example: 200 + format: int64 + type: integer + rawData: + description: JSON-encoded string representing the widget state. + example: '{"widgetType":"timeseries","requests":[]}' + type: string + watermark: + description: Hex-encoded watermark string identifying the widget. + example: "0123456789abcdef" + type: string + required: + - rawData + - watermark + - locationx + - locationy + type: object + StegadographyWidgetItems: + description: List of watermarked widget resources recovered from an image. + example: + - attributes: + locationx: 100 + locationy: 200 + rawData: '{"widgetType":"timeseries","requests":[]}' + watermark: "0123456789abcdef" + id: "abc123:0123456789abcdef" + type: widget + items: + $ref: "#/components/schemas/StegadographyWidget" + type: array + StegadographyWidgetType: + description: Stegadography widget resource type. + enum: + - widget + example: widget + type: string + x-enum-varnames: + - WIDGET Step: description: A Step is a sub-component of a workflow. Each Step performs an action. properties: @@ -161903,6 +161986,75 @@ paths: - status_pages_settings_write - status_pages_public_page_publish - status_pages_internal_page_publish + /api/v2/stegadography/get-widgets: + post: + description: |- + Extracts watermarks from a PNG image and returns the cached widget data + associated with each watermark found. The image must be uploaded as a + `multipart/form-data` request with the file in the `image` field. + Only widgets belonging to the authenticated organization are returned. + operationId: GetStegadographyWidgets + requestBody: + content: + multipart/form-data: + examples: + default: + value: + image: "screenshot.png" + schema: + $ref: "#/components/schemas/StegadographyGetWidgetsRequest" + description: PNG image to extract watermarks from. + required: true + responses: + "200": + content: + application/json: + examples: + default: + value: + data: + - attributes: + locationx: 100 + locationy: 200 + rawData: '{"widgetType":"timeseries","requests":[]}' + watermark: "0123456789abcdef" + id: "abc123:0123456789abcdef" + type: widget + schema: + $ref: "#/components/schemas/StegadographyGetWidgetsResponse" + description: OK + "400": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Bad Request + "403": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Forbidden + "415": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Unsupported Media Type + "429": + $ref: "#/components/responses/TooManyRequestsResponse" + "500": + content: + application/json: + schema: + $ref: "#/components/schemas/JSONAPIErrorResponse" + description: Internal Server Error + security: + - apiKeyAuth: [] + appKeyAuth: [] + summary: Get widgets from an image + tags: + - Stegadography /api/v2/synthetics/api-multistep/subtests/{public_id}: get: description: |- @@ -170201,6 +170353,8 @@ tags: name: Static Analysis - description: Manage your status pages and communicate service disruptions to stakeholders via Datadog's API. See the [Status Pages documentation](https://docs.datadoghq.com/incident_response/status_pages/) for more information. name: Status Pages + - description: Extract watermarks embedded in dashboard screenshots to retrieve cached widget state. + name: Stegadography - description: |- Enable Storage Management for S3 buckets, GCS buckets, and Azure containers. Each configuration registers the destination that holds inventory reports for the storage being monitored. name: Storage Management diff --git a/examples/v2/stegadography/GetStegadographyWidgets.ts b/examples/v2/stegadography/GetStegadographyWidgets.ts new file mode 100644 index 000000000000..6d7e03e22bea --- /dev/null +++ b/examples/v2/stegadography/GetStegadographyWidgets.ts @@ -0,0 +1,17 @@ +/** + * Get widgets from an image returns "OK" response + */ + +import { client, v2 } from "@datadog/datadog-api-client"; + +const configuration = client.createConfiguration(); +const apiInstance = new v2.StegadographyApi(configuration); + +apiInstance + .getStegadographyWidgets() + .then((data: v2.StegadographyGetWidgetsResponse) => { + console.log( + "API called successfully. Returned data: " + JSON.stringify(data) + ); + }) + .catch((error: any) => console.error(error)); diff --git a/features/support/scenarios_model_mapping.ts b/features/support/scenarios_model_mapping.ts index ea252e295e68..d1c090b08188 100644 --- a/features/support/scenarios_model_mapping.ts +++ b/features/support/scenarios_model_mapping.ts @@ -14272,6 +14272,13 @@ export const ScenariosModelMappings: {[key: string]: {[key: string]: any}} = { }, "operationResponseType": "{}", }, + "v2.GetStegadographyWidgets": { + "image": { + "type": "HttpFile", + "format": "binary", + }, + "operationResponseType": "StegadographyGetWidgetsResponse", + }, "v2.GetApiMultistepSubtests": { "publicId": { "type": "string", diff --git a/features/v2/stegadography.feature b/features/v2/stegadography.feature new file mode 100644 index 000000000000..074f179559c5 --- /dev/null +++ b/features/v2/stegadography.feature @@ -0,0 +1,25 @@ +@endpoint(stegadography) @endpoint(stegadography-v2) +Feature: Stegadography + Extract watermarks embedded in dashboard screenshots to retrieve cached + widget state. + + Background: + Given a valid "apiKeyAuth" key in the system + And a valid "appKeyAuth" key in the system + And an instance of "Stegadography" API + And new "GetStegadographyWidgets" request + + @generated @skip @team:DataDog/dataviz-backend-maintainers + Scenario: Get widgets from an image returns "Bad Request" response + When the request is sent + Then the response status is 400 Bad Request + + @generated @skip @team:DataDog/dataviz-backend-maintainers + Scenario: Get widgets from an image returns "OK" response + When the request is sent + Then the response status is 200 OK + + @generated @skip @team:DataDog/dataviz-backend-maintainers + Scenario: Get widgets from an image returns "Unsupported Media Type" response + When the request is sent + Then the response status is 415 Unsupported Media Type diff --git a/features/v2/undo.json b/features/v2/undo.json index b6003df86834..32dd3bda46f2 100644 --- a/features/v2/undo.json +++ b/features/v2/undo.json @@ -7640,6 +7640,12 @@ "type": "idempotent" } }, + "GetStegadographyWidgets": { + "tag": "Stegadography", + "undo": { + "type": "safe" + } + }, "GetApiMultistepSubtests": { "tag": "Synthetics", "undo": { diff --git a/packages/datadog-api-client-v2/apis/StegadographyApi.ts b/packages/datadog-api-client-v2/apis/StegadographyApi.ts new file mode 100644 index 000000000000..4a91b64c2188 --- /dev/null +++ b/packages/datadog-api-client-v2/apis/StegadographyApi.ts @@ -0,0 +1,206 @@ +import { + BaseAPIRequestFactory, + RequiredError, +} from "../../datadog-api-client-common/baseapi"; +import { + Configuration, + applySecurityAuthentication, +} from "../../datadog-api-client-common/configuration"; +import { + RequestContext, + HttpMethod, + ResponseContext, + HttpFile, +} from "../../datadog-api-client-common/http/http"; + +import FormData from "form-data"; + +import { logger } from "../../../logger"; +import { ObjectSerializer } from "../models/ObjectSerializer"; +import { ApiException } from "../../datadog-api-client-common/exception"; + +import { APIErrorResponse } from "../models/APIErrorResponse"; +import { JSONAPIErrorResponse } from "../models/JSONAPIErrorResponse"; +import { StegadographyGetWidgetsResponse } from "../models/StegadographyGetWidgetsResponse"; + +export class StegadographyApiRequestFactory extends BaseAPIRequestFactory { + public async getStegadographyWidgets( + image: HttpFile, + _options?: Configuration + ): Promise { + const _config = _options || this.configuration; + + // verify required parameter 'image' is not null or undefined + if (image === null || image === undefined) { + throw new RequiredError("image", "getStegadographyWidgets"); + } + + // Path Params + const localVarPath = "/api/v2/stegadography/get-widgets"; + + // Make Request Context + const requestContext = _config + .getServer("v2.StegadographyApi.getStegadographyWidgets") + .makeRequestContext(localVarPath, HttpMethod.POST); + requestContext.setHeaderParam("Accept", "application/json"); + requestContext.setHttpConfig(_config.httpConfig); + + // Form Params + const localVarFormParams = new FormData(); + if (image !== undefined) { + // TODO: replace .append with .set + localVarFormParams.append("image", image.data, image.name); + } + requestContext.setBody(localVarFormParams); + + // Apply auth methods + applySecurityAuthentication(_config, requestContext, [ + "apiKeyAuth", + "appKeyAuth", + ]); + + return requestContext; + } +} + +export class StegadographyApiResponseProcessor { + /** + * Unwraps the actual response sent by the server from the response context and deserializes the response content + * to the expected objects + * + * @params response Response returned by the server for a request to getStegadographyWidgets + * @throws ApiException if the response code was not in [200, 299] + */ + public async getStegadographyWidgets( + response: ResponseContext + ): Promise { + const contentType = ObjectSerializer.normalizeMediaType( + response.headers["content-type"] + ); + if (response.httpStatusCode === 200) { + const body: StegadographyGetWidgetsResponse = + ObjectSerializer.deserialize( + ObjectSerializer.parse(await response.body.text(), contentType), + "StegadographyGetWidgetsResponse" + ) as StegadographyGetWidgetsResponse; + return body; + } + if ( + response.httpStatusCode === 400 || + response.httpStatusCode === 403 || + response.httpStatusCode === 415 || + response.httpStatusCode === 500 + ) { + const bodyText = ObjectSerializer.parse( + await response.body.text(), + contentType + ); + let body: JSONAPIErrorResponse; + try { + body = ObjectSerializer.deserialize( + bodyText, + "JSONAPIErrorResponse" + ) as JSONAPIErrorResponse; + } catch (error) { + logger.debug(`Got error deserializing error: ${error}`); + throw new ApiException( + response.httpStatusCode, + bodyText + ); + } + throw new ApiException( + response.httpStatusCode, + body + ); + } + if (response.httpStatusCode === 429) { + const bodyText = ObjectSerializer.parse( + await response.body.text(), + contentType + ); + let body: APIErrorResponse; + try { + body = ObjectSerializer.deserialize( + bodyText, + "APIErrorResponse" + ) as APIErrorResponse; + } catch (error) { + logger.debug(`Got error deserializing error: ${error}`); + throw new ApiException( + response.httpStatusCode, + bodyText + ); + } + throw new ApiException(response.httpStatusCode, body); + } + + // Work around for missing responses in specification, e.g. for petstore.yaml + if (response.httpStatusCode >= 200 && response.httpStatusCode <= 299) { + const body: StegadographyGetWidgetsResponse = + ObjectSerializer.deserialize( + ObjectSerializer.parse(await response.body.text(), contentType), + "StegadographyGetWidgetsResponse", + "" + ) as StegadographyGetWidgetsResponse; + return body; + } + + const body = (await response.body.text()) || ""; + throw new ApiException( + response.httpStatusCode, + 'Unknown API Status Code!\nBody: "' + body + '"' + ); + } +} + +export interface StegadographyApiGetStegadographyWidgetsRequest { + /** + * PNG image to extract watermarks from. + * @type HttpFile + */ + image: HttpFile; +} + +export class StegadographyApi { + private requestFactory: StegadographyApiRequestFactory; + private responseProcessor: StegadographyApiResponseProcessor; + private configuration: Configuration; + + public constructor( + configuration: Configuration, + requestFactory?: StegadographyApiRequestFactory, + responseProcessor?: StegadographyApiResponseProcessor + ) { + this.configuration = configuration; + this.requestFactory = + requestFactory || new StegadographyApiRequestFactory(configuration); + this.responseProcessor = + responseProcessor || new StegadographyApiResponseProcessor(); + } + + /** + * Extracts watermarks from a PNG image and returns the cached widget data + * associated with each watermark found. The image must be uploaded as a + * `multipart/form-data` request with the file in the `image` field. + * Only widgets belonging to the authenticated organization are returned. + * @param param The request object + */ + public getStegadographyWidgets( + param: StegadographyApiGetStegadographyWidgetsRequest, + options?: Configuration + ): Promise { + const requestContextPromise = this.requestFactory.getStegadographyWidgets( + param.image, + options + ); + return requestContextPromise.then((requestContext) => { + return this.configuration.httpApi + .send(requestContext) + .then((responseContext) => { + return this.responseProcessor.getStegadographyWidgets( + responseContext + ); + }); + }); + } +} diff --git a/packages/datadog-api-client-v2/index.ts b/packages/datadog-api-client-v2/index.ts index c8bbc3d1076c..aa021efa806d 100644 --- a/packages/datadog-api-client-v2/index.ts +++ b/packages/datadog-api-client-v2/index.ts @@ -1419,6 +1419,11 @@ export { StatusPagesApi, } from "./apis/StatusPagesApi"; +export { + StegadographyApiGetStegadographyWidgetsRequest, + StegadographyApi, +} from "./apis/StegadographyApi"; + export { StorageManagementApiDeleteSyncConfigRequest, StorageManagementApiUpsertSyncConfigRequest, @@ -6767,6 +6772,10 @@ export { StatusPagesComponentGroupType } from "./models/StatusPagesComponentGrou export { StatusPagesUser } from "./models/StatusPagesUser"; export { StatusPagesUserAttributes } from "./models/StatusPagesUserAttributes"; export { StatusPagesUserType } from "./models/StatusPagesUserType"; +export { StegadographyGetWidgetsResponse } from "./models/StegadographyGetWidgetsResponse"; +export { StegadographyWidget } from "./models/StegadographyWidget"; +export { StegadographyWidgetAttributes } from "./models/StegadographyWidgetAttributes"; +export { StegadographyWidgetType } from "./models/StegadographyWidgetType"; export { Step } from "./models/Step"; export { StepDisplay } from "./models/StepDisplay"; export { StepDisplayBounds } from "./models/StepDisplayBounds"; diff --git a/packages/datadog-api-client-v2/models/ObjectSerializer.ts b/packages/datadog-api-client-v2/models/ObjectSerializer.ts index ff03d52b87a5..5a32a609d99a 100644 --- a/packages/datadog-api-client-v2/models/ObjectSerializer.ts +++ b/packages/datadog-api-client-v2/models/ObjectSerializer.ts @@ -3978,6 +3978,9 @@ import { StatusPagesComponentGroupRelationshipsStatusPage } from "./StatusPagesC import { StatusPagesComponentGroupRelationshipsStatusPageData } from "./StatusPagesComponentGroupRelationshipsStatusPageData"; import { StatusPagesUser } from "./StatusPagesUser"; import { StatusPagesUserAttributes } from "./StatusPagesUserAttributes"; +import { StegadographyGetWidgetsResponse } from "./StegadographyGetWidgetsResponse"; +import { StegadographyWidget } from "./StegadographyWidget"; +import { StegadographyWidgetAttributes } from "./StegadographyWidgetAttributes"; import { Step } from "./Step"; import { StepDisplay } from "./StepDisplay"; import { StepDisplayBounds } from "./StepDisplayBounds"; @@ -6832,6 +6835,7 @@ const enumsMap: { [key: string]: any[] } = { StatusPagesComponentGroupAttributesComponentsItemsType: ["component"], StatusPagesComponentGroupType: ["components"], StatusPagesUserType: ["users"], + StegadographyWidgetType: ["widget"], SuiteJsonPatchType: ["suites_json_patch"], SuiteSearchResponseType: ["suites_search"], SyntheticsApiMultistepParentTestType: ["parent_test"], @@ -11990,6 +11994,9 @@ const typeMap: { [index: string]: any } = { StatusPagesComponentGroupRelationshipsStatusPageData, StatusPagesUser: StatusPagesUser, StatusPagesUserAttributes: StatusPagesUserAttributes, + StegadographyGetWidgetsResponse: StegadographyGetWidgetsResponse, + StegadographyWidget: StegadographyWidget, + StegadographyWidgetAttributes: StegadographyWidgetAttributes, Step: Step, StepDisplay: StepDisplay, StepDisplayBounds: StepDisplayBounds, diff --git a/packages/datadog-api-client-v2/models/StegadographyGetWidgetsResponse.ts b/packages/datadog-api-client-v2/models/StegadographyGetWidgetsResponse.ts new file mode 100644 index 000000000000..6baa5c395449 --- /dev/null +++ b/packages/datadog-api-client-v2/models/StegadographyGetWidgetsResponse.ts @@ -0,0 +1,54 @@ +/** + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2020-Present Datadog, Inc. + */ +import { StegadographyWidget } from "./StegadographyWidget"; + +import { AttributeTypeMap } from "../../datadog-api-client-common/util"; + +/** + * Response containing watermarked widgets recovered from an image. + */ +export class StegadographyGetWidgetsResponse { + /** + * List of watermarked widget resources recovered from an image. + */ + "data": Array; + + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + data: { + baseName: "data", + type: "Array", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return StegadographyGetWidgetsResponse.attributeTypeMap; + } + + public constructor() {} +} diff --git a/packages/datadog-api-client-v2/models/StegadographyWidget.ts b/packages/datadog-api-client-v2/models/StegadographyWidget.ts new file mode 100644 index 000000000000..fa5a5991b8da --- /dev/null +++ b/packages/datadog-api-client-v2/models/StegadographyWidget.ts @@ -0,0 +1,73 @@ +/** + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2020-Present Datadog, Inc. + */ +import { StegadographyWidgetAttributes } from "./StegadographyWidgetAttributes"; +import { StegadographyWidgetType } from "./StegadographyWidgetType"; + +import { AttributeTypeMap } from "../../datadog-api-client-common/util"; + +/** + * A single watermarked widget resource recovered from an image. + */ +export class StegadographyWidget { + /** + * Attributes of a watermarked widget recovered from an image. + */ + "attributes": StegadographyWidgetAttributes; + /** + * Composite identifier formed from the organization ID and watermark, separated by a colon. + */ + "id": string; + /** + * Stegadography widget resource type. + */ + "type": StegadographyWidgetType; + + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + attributes: { + baseName: "attributes", + type: "StegadographyWidgetAttributes", + required: true, + }, + id: { + baseName: "id", + type: "string", + required: true, + }, + type: { + baseName: "type", + type: "StegadographyWidgetType", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return StegadographyWidget.attributeTypeMap; + } + + public constructor() {} +} diff --git a/packages/datadog-api-client-v2/models/StegadographyWidgetAttributes.ts b/packages/datadog-api-client-v2/models/StegadographyWidgetAttributes.ts new file mode 100644 index 000000000000..c3375564d358 --- /dev/null +++ b/packages/datadog-api-client-v2/models/StegadographyWidgetAttributes.ts @@ -0,0 +1,82 @@ +/** + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2020-Present Datadog, Inc. + */ + +import { AttributeTypeMap } from "../../datadog-api-client-common/util"; + +/** + * Attributes of a watermarked widget recovered from an image. + */ +export class StegadographyWidgetAttributes { + /** + * Horizontal pixel coordinate where the watermark was found in the image. + */ + "locationx": number; + /** + * Vertical pixel coordinate where the watermark was found in the image. + */ + "locationy": number; + /** + * JSON-encoded string representing the widget state. + */ + "rawData": string; + /** + * Hex-encoded watermark string identifying the widget. + */ + "watermark": string; + + /** + * A container for additional, undeclared properties. + * This is a holder for any undeclared properties as specified with + * the 'additionalProperties' keyword in the OAS document. + */ + "additionalProperties"?: { [key: string]: any }; + + /** + * @ignore + */ + "_unparsed"?: boolean; + + /** + * @ignore + */ + static readonly attributeTypeMap: AttributeTypeMap = { + locationx: { + baseName: "locationx", + type: "number", + required: true, + format: "int64", + }, + locationy: { + baseName: "locationy", + type: "number", + required: true, + format: "int64", + }, + rawData: { + baseName: "rawData", + type: "string", + required: true, + }, + watermark: { + baseName: "watermark", + type: "string", + required: true, + }, + additionalProperties: { + baseName: "additionalProperties", + type: "{ [key: string]: any; }", + }, + }; + + /** + * @ignore + */ + static getAttributeTypeMap(): AttributeTypeMap { + return StegadographyWidgetAttributes.attributeTypeMap; + } + + public constructor() {} +} diff --git a/packages/datadog-api-client-v2/models/StegadographyWidgetType.ts b/packages/datadog-api-client-v2/models/StegadographyWidgetType.ts new file mode 100644 index 000000000000..af6e3860e484 --- /dev/null +++ b/packages/datadog-api-client-v2/models/StegadographyWidgetType.ts @@ -0,0 +1,14 @@ +/** + * Unless explicitly stated otherwise all files in this repository are licensed under the Apache-2.0 License. + * This product includes software developed at Datadog (https://www.datadoghq.com/). + * Copyright 2020-Present Datadog, Inc. + */ + +import { UnparsedObject } from "../../datadog-api-client-common/util"; + +/** + * Stegadography widget resource type. + */ + +export type StegadographyWidgetType = typeof WIDGET | UnparsedObject; +export const WIDGET = "widget";