Skip to content

Commit

Permalink
FreePass User ID Module : initial release (#9814)
Browse files Browse the repository at this point in the history
* Add FreePass IdSystem

* Update IdSystem doc

* Add contact email

* Ensure freepassData is optional

* Update readme with more specific details

* Update readme

* Update official contact email

* Add md code type

Trigger ci

* Replace double with singe quote in test
  • Loading branch information
czarpino authored Jun 7, 2023
1 parent 254f098 commit bdd56a7
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 1 deletion.
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@
"verizonMediaIdSystem",
"zeotapIdPlusIdSystem",
"adqueryIdSystem",
"gravitoIdSystem"
"gravitoIdSystem",
"freepassIdSystem"
],
"adpod": [
"freeWheelAdserverVideo",
Expand Down
61 changes: 61 additions & 0 deletions modules/freepassIdSystem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { submodule } from '../src/hook.js';
import {generateUUID, logMessage} from '../src/utils.js';

const MODULE_NAME = 'freepassId';

export const freepassIdSubmodule = {
name: MODULE_NAME,
decode: function (value, config) {
logMessage('Decoding FreePass ID: ', value);

return { [MODULE_NAME]: value };
},

getId: function (config, consent, cachedIdObject) {
logMessage('Getting FreePass ID using config: ' + JSON.stringify(config));

const freepassData = config.params !== undefined ? (config.params.freepassData || {}) : {}
let idObject = {userId: generateUUID()};

if (freepassData.commonId !== undefined) {
idObject.commonId = config.params.freepassData.commonId;
}

if (freepassData.userIp !== undefined) {
idObject.userIp = config.params.freepassData.userIp;
}

return {id: idObject};
},

extendId: function (config, consent, cachedIdObject) {
let freepassData = config.params.freepassData;
let hasFreepassData = freepassData !== undefined;
if (!hasFreepassData) {
logMessage('No Freepass Data. CachedIdObject will not be extended: ' + JSON.stringify(cachedIdObject));
return {
id: cachedIdObject
};
}

if (freepassData.commonId === cachedIdObject.commonId && freepassData.userIp === cachedIdObject.userIp) {
logMessage('FreePass ID is already up-to-date: ' + JSON.stringify(cachedIdObject));
return {
id: cachedIdObject
};
}

logMessage('Extending FreePass ID object: ' + JSON.stringify(cachedIdObject));
logMessage('Extending FreePass ID using config: ' + JSON.stringify(config));

return {
id: {
commonId: freepassData.commonId,
userIp: freepassData.userIp,
userId: cachedIdObject.userId,
},
};
}
};

submodule('userId', freepassIdSubmodule);
47 changes: 47 additions & 0 deletions modules/freepassIdSystem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
## FreePass User ID Submodule

[FreePass](https://freepass-login.com/introduction.html) is a common authentication service operated by Freebit Co., Ltd. Users with a FreePass account do not need to create a new account to use partner services.

# General Information

Please contact FreePass before using this ID.

```
Module Name: FreePass Id System
Module Type: User Id System
Maintainer: freepass-headerbidding@craid-inc.com
```

## Building Prebid with FreePass ID Support

First, make sure to add the FreePass ID submodule to your Prebid.js package with:

```shell
gulp build --modules=freepassIdSystem,userId
```

The following configuration parameters are available:

```javascript
pbjs.setConfig({
userSync: {
userIds: [{
name: 'freepassId',
params: {
freepassData: {
commonId: 'fpcommonid123',
userIp: '127.0.0.1'
}
}
}]
}
});
```

| Param under userSync.userIds[] | Scope | Type | Description | Example |
|--------------------------------|----------|--------|------------------------------------------------------|----------------|
| name | Required | String | The name of this module | `"freepassId"` |
| freepassData | Optional | Object | FreePass data | `{}` |
| freepassData.commonId | Optional | String | Common ID obtained from FreePass | `"abcd1234"` |
| freepassData.userIp | Optional | String | User IP obtained in cooperation with partner service | `"127.0.0.1"` |

186 changes: 186 additions & 0 deletions test/spec/modules/freepassIdSystem_spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import {freepassIdSubmodule} from 'modules/freepassIdSystem';
import sinon from 'sinon';
import * as utils from '../../../src/utils';

let expect = require('chai').expect;

describe('FreePass ID System', function () {
const UUID = '15fde1dc-1861-4894-afdf-b757272f3568';

before(function () {
sinon.stub(utils, 'generateUUID').returns(UUID);
sinon.stub(utils, 'logMessage');
});

after(function () {
utils.generateUUID.restore();
utils.logMessage.restore();
});

describe('freepassIdSubmodule', function () {
it('should expose submodule name', function () {
expect(freepassIdSubmodule.name).to.equal('freepassId');
});
});

describe('getId', function () {
const config = {
storage: {
name: '_freepassId',
type: 'cookie',
expires: 30
},
params: {
freepassData: {
commonId: 'commonId',
userIp: '127.0.0.1'
}
}
};

it('should return an IdObject with a UUID', function () {
const objectId = freepassIdSubmodule.getId(config, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.userId).to.equal(UUID);
});

it('should include userIp in IdObject', function () {
const objectId = freepassIdSubmodule.getId(config, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.userIp).to.equal('127.0.0.1');
});
it('should skip userIp in IdObject if not available', function () {
const localConfig = Object.assign({}, config);
delete localConfig.params.freepassData.userIp;
const objectId = freepassIdSubmodule.getId(localConfig, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.userIp).to.be.undefined;
});
it('should skip userIp in IdObject if freepassData is not available', function () {
const localConfig = JSON.parse(JSON.stringify(config));
delete localConfig.params.freepassData;
const objectId = freepassIdSubmodule.getId(localConfig, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.userIp).to.be.undefined;
});
it('should skip userIp in IdObject if params is not available', function () {
const localConfig = JSON.parse(JSON.stringify(config));
delete localConfig.params;
const objectId = freepassIdSubmodule.getId(localConfig, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.userIp).to.be.undefined;
});
it('should include commonId in IdObject', function () {
const objectId = freepassIdSubmodule.getId(config, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.commonId).to.equal('commonId');
});
it('should skip commonId in IdObject if not available', function () {
const localConfig = Object.assign({}, config);
delete localConfig.params.freepassData.commonId;
const objectId = freepassIdSubmodule.getId(localConfig, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.commonId).to.be.undefined;
});
it('should skip commonId in IdObject if freepassData is not available', function () {
const localConfig = JSON.parse(JSON.stringify(config));
delete localConfig.params.freepassData;
const objectId = freepassIdSubmodule.getId(localConfig, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.commonId).to.be.undefined;
});
it('should skip commonId in IdObject if params is not available', function () {
const localConfig = JSON.parse(JSON.stringify(config));
delete localConfig.params;
const objectId = freepassIdSubmodule.getId(localConfig, undefined);
expect(objectId).to.be.an('object');
expect(objectId.id).to.be.an('object');
expect(objectId.id.commonId).to.be.undefined;
});
});

describe('decode', function () {
it('should have module name as property', function () {
const decodedId = freepassIdSubmodule.decode({}, {});
expect(decodedId).to.be.an('object');
expect(decodedId).to.have.property('freepassId');
});
it('should have IObject as property value', function () {
const idObject = {
commonId: 'commonId',
userIp: '127.0.0.1',
userId: UUID
};
const decodedId = freepassIdSubmodule.decode(idObject, {});
expect(decodedId).to.be.an('object');
expect(decodedId.freepassId).to.be.an('object');
expect(decodedId.freepassId).to.equal(idObject);
});
});

describe('extendId', function () {
const config = {
storage: {
name: '_freepassId',
type: 'cookie',
expires: 30
},
params: {
freepassData: {
commonId: 'commonId',
userIp: '127.0.0.1'
}
}
};

it('should return cachedIdObject if there are no changes', function () {
const idObject = freepassIdSubmodule.getId(config, undefined);
const cachedIdObject = Object.assign({}, idObject.id);
const extendedIdObject = freepassIdSubmodule.extendId(config, undefined, cachedIdObject);
expect(extendedIdObject).to.be.an('object');
expect(extendedIdObject.id).to.be.an('object');
expect(extendedIdObject.id).to.equal(cachedIdObject);
});

it('should return cachedIdObject if there are no new data', function () {
const idObject = freepassIdSubmodule.getId(config, undefined);
const cachedIdObject = Object.assign({}, idObject.id);
const localConfig = JSON.parse(JSON.stringify(config));
delete localConfig.params.freepassData;
const extendedIdObject = freepassIdSubmodule.extendId(localConfig, undefined, cachedIdObject);
expect(extendedIdObject).to.be.an('object');
expect(extendedIdObject.id).to.be.an('object');
expect(extendedIdObject.id).to.equal(cachedIdObject);
});

it('should return new commonId if there are changes', function () {
const idObject = freepassIdSubmodule.getId(config, undefined);
const cachedIdObject = Object.assign({}, idObject.id);
const localConfig = JSON.parse(JSON.stringify(config));
localConfig.params.freepassData.commonId = 'newCommonId';
const extendedIdObject = freepassIdSubmodule.extendId(localConfig, undefined, cachedIdObject);
expect(extendedIdObject).to.be.an('object');
expect(extendedIdObject.id).to.be.an('object');
expect(extendedIdObject.id.commonId).to.equal('newCommonId');
});

it('should return new userIp if there are changes', function () {
const idObject = freepassIdSubmodule.getId(config, undefined);
const cachedIdObject = Object.assign({}, idObject.id);
const localConfig = JSON.parse(JSON.stringify(config));
localConfig.params.freepassData.userIp = '192.168.1.1';
const extendedIdObject = freepassIdSubmodule.extendId(localConfig, undefined, cachedIdObject);
expect(extendedIdObject).to.be.an('object');
expect(extendedIdObject.id).to.be.an('object');
expect(extendedIdObject.id.userIp).to.equal('192.168.1.1');
});
});
});

0 comments on commit bdd56a7

Please sign in to comment.