Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FreePass User ID Module : initial release #9814

Merged
merged 10 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion modules/.submodules.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,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: [email protected]
```

## 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');
});
});
});