Skip to content

Commit

Permalink
feat: facebook custom audience app secret support (#3357)
Browse files Browse the repository at this point in the history
* feat: facebook custom audience app secret support

* fix: review comment addressed

* fix: add test case description
  • Loading branch information
shrouti1507 authored May 15, 2024
1 parent 265a71d commit fce4ef9
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 3 deletions.
9 changes: 8 additions & 1 deletion src/v0/destinations/fb_custom_audience/transform.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const {
prepareDataField,
getSchemaForEventMappedToDest,
batchingWithPayloadSize,
generateAppSecretProof,
} = require('./util');
const {
getEndPoint,
Expand Down Expand Up @@ -88,7 +89,7 @@ const prepareResponse = (
userSchema,
isHashRequired = true,
) => {
const { accessToken, disableFormat, type, subType, isRaw } = destination.Config;
const { accessToken, disableFormat, type, subType, isRaw, appSecret } = destination.Config;

const mappedToDestination = get(message, MappedToDestinationKey);

Expand All @@ -105,6 +106,12 @@ const prepareResponse = (

prepareParams.access_token = accessToken;

if (isDefinedAndNotNullAndNotEmpty(appSecret)) {
const dateNow = Date.now();
prepareParams.appsecret_time = Math.floor(dateNow / 1000); // Get current Unix time in seconds
prepareParams.appsecret_proof = generateAppSecretProof(accessToken, appSecret, dateNow);
}

// creating the payload field for parameters
if (isRaw) {
paramsPayload.is_raw = isRaw;
Expand Down
22 changes: 21 additions & 1 deletion src/v0/destinations/fb_custom_audience/util.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const lodash = require('lodash');
const sha256 = require('sha256');
const crypto = require('crypto');
const get = require('get-value');
const jsonSize = require('json-size');
const { InstrumentationError, ConfigurationError } = require('@rudderstack/integrations-lib');
Expand Down Expand Up @@ -206,4 +207,23 @@ const prepareDataField = (
return data;
};

module.exports = { prepareDataField, getSchemaForEventMappedToDest, batchingWithPayloadSize };
// ref: https://developers.facebook.com/docs/facebook-login/security/#generate-the-proof

const generateAppSecretProof = (accessToken, appSecret, dateNow) => {
const currentTime = Math.floor(dateNow / 1000); // Get current Unix time in seconds
const data = `${accessToken}|${currentTime}`;

// Creating a HMAC SHA-256 hash with the app_secret as the key
const hmac = crypto.createHmac('sha256', appSecret);
hmac.update(data);
const appsecretProof = hmac.digest('hex');

return appsecretProof;
};

module.exports = {
prepareDataField,
getSchemaForEventMappedToDest,
batchingWithPayloadSize,
generateAppSecretProof,
};
152 changes: 151 additions & 1 deletion test/integrations/destinations/fb_custom_audience/processor/data.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { getEndPoint } from '../../../../../src/v0/destinations/fb_custom_audience/config';

export const mockFns = (_) => {
// @ts-ignore
jest.useFakeTimers().setSystemTime(new Date('2023-10-15'));
};

export const data = [
{
name: 'fb_custom_audience',
Expand Down Expand Up @@ -54463,4 +54468,149 @@ export const data = [
},
},
},
];
{
name: 'fb_custom_audience',
description:
'If App secret is configured in the UI, appsecret_proof and appsecret_time will be added to destination request.',
feature: 'processor',
module: 'destination',
version: 'v0',
input: {
request: {
body: [
{
message: {
userId: 'user 1',
anonymousId: 'anon-id-new',
event: 'event1',
type: 'audiencelist',
properties: {
listData: {
add: [
{
EMAIL: '[email protected]',
DOBM: '2',
DOBD: '13',
DOBY: '2013',
PHONE: '@09432457768',
GEN: 'f',
FI: 'Ms.',
MADID: 'ABC',
ZIP: 'ZIP ',
ST: '123abc ',
COUNTRY: 'IN',
},
],
},
},
context: {
ip: '14.5.67.21',
library: {
name: 'http',
},
},
timestamp: '2020-02-02T00:23:09.544Z',
},
destination: {
Config: {
accessToken: 'ABC',
appSecret: 'dummySecret',
userSchema: [
'EMAIL',
'DOBM',
'DOBD',
'DOBY',
'PHONE',
'GEN',
'FI',
'MADID',
'ZIP',
'ST',
'COUNTRY',
],
isHashRequired: false,
disableFormat: false,
audienceId: 'aud1',
isRaw: true,
type: 'NA',
subType: 'ANYTHING',
maxUserCount: '50',
},
Enabled: true,
Transformations: [],
IsProcessorEnabled: true,
},
libraries: [],
request: {
query: {},
},
},
],
},
},
output: {
response: {
status: 200,
body: [
{
output: {
version: '1',
type: 'REST',
method: 'POST',
endpoint: getEndPoint('aud1'),
headers: {},
params: {
access_token: 'ABC',
appsecret_proof: 'd103874f3b5f01f57c4f84edfb96ac94055da8f83c2b45e6f26dafca9188ff4d',
appsecret_time: 1697328000,
payload: {
is_raw: true,
data_source: {
sub_type: 'ANYTHING',
},
schema: [
'EMAIL',
'DOBM',
'DOBD',
'DOBY',
'PHONE',
'GEN',
'FI',
'MADID',
'ZIP',
'ST',
'COUNTRY',
],
data: [
[
'[email protected]',
'2',
'13',
'2013',
'@09432457768',
'f',
'Ms.',
'ABC',
'ZIP ',
'123abc ',
'IN',
],
],
},
},
userId: '',
body: {
JSON: {},
XML: {},
JSON_ARRAY: {},
FORM: {},
},
files: {},
},
statusCode: 200,
},
],
},
},
},
].map((d) => ({ ...d, mockFns }));

0 comments on commit fce4ef9

Please sign in to comment.