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

Remove consent storage limit for viewer #34054

Merged
merged 2 commits into from
May 6, 2021
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
40 changes: 2 additions & 38 deletions extensions/amp-consent/0.1/consent-state-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,12 @@ import {
import {Deferred} from '../../../src/core/data-structures/promise';
import {Services} from '../../../src/services';
import {assertHttpsUrl} from '../../../src/url';
import {dev, devAssert, user} from '../../../src/log';
import {dict, hasOwn} from '../../../src/core/types/object';
import {dev, devAssert} from '../../../src/log';
import {expandConsentEndpointUrl, getConsentCID} from './consent-config';
import {hasOwn} from '../../../src/core/types/object';

const TAG = 'CONSENT-STATE-MANAGER';

/** @visibleForTesting */
export const CONSENT_STORAGE_MAX = 1200;

export class ConsentStateManager {
/**
* Creates an instance of ConsentStateManager.
Expand Down Expand Up @@ -447,39 +444,6 @@ export class ConsentInstance {
return;
}

// Check size
const size = JSON.stringify(
dict({
[this.storageKey_]: value,
})
).length;

if (size > CONSENT_STORAGE_MAX) {
// Size restriction only applies to documents servered from a viewer
// that implements the storage API.
const usesViewerStorage = storage.isViewerStorage();
if (usesViewerStorage) {
// 1200 * 4/3 (base64) = 1600 bytes
user().error(
TAG,
'Cannot store consent information which length exceeds %s. ' +
'Previous stored consentInfo will be cleared',
CONSENT_STORAGE_MAX
);
// If new consentInfo value cannot be stored, need to remove previous
// value
storage.remove(this.storageKey_);
// TODO: Good to have a way to inform CMP service in this case
return;
}
user().info(
TAG,
'Current consent information length exceeds %s ' +
'and will not be stored when the page is served ' +
'from a viewer that supports the Local Storage API.',
CONSENT_STORAGE_MAX
);
}
this.savedConsentInfo_ = consentInfo;
storage.setNonBoolean(this.storageKey_, value);
this.sendUpdateHrefRequest_(consentInfo);
Expand Down
67 changes: 1 addition & 66 deletions extensions/amp-consent/0.1/test/test-consent-state-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,8 @@ import {
constructConsentInfo,
constructMetadata,
} from '../consent-info';
import {
CONSENT_STORAGE_MAX,
ConsentInstance,
ConsentStateManager,
} from '../consent-state-manager';
import {CONSENT_STRING_TYPE} from '../../../../src/core/constants/consent-state';
import {ConsentInstance, ConsentStateManager} from '../consent-state-manager';
import {Services} from '../../../../src/services';
import {dev} from '../../../../src/log';
import {macroTask} from '../../../../testing/yield';
Expand Down Expand Up @@ -194,35 +190,6 @@ describes.realWin('ConsentStateManager', {amp: 1}, (env) => {
)
);
});

it('update consent string that exceeds max size', async () => {
expectAsyncConsoleError(/Cannot store consent information/);
manager.registerConsentInstance('test', {});
let testStr = 'a';
// Reserve 26 chars to metadata size `"m":{"cst":1,"ac":"12345"}`
// Reserve 36 chars to the storage key, `''` and `{}`
// Leaves CONSENT_STORAGE_MAX - 62 chars to consent string
for (let i = 0; i < CONSENT_STORAGE_MAX - 62; i++) {
testStr += 'a';
}
manager.updateConsentInstancePurposes({
'purpose-abc': PURPOSE_CONSENT_STATE.ACCEPTED,
});
manager.updateConsentInstanceState(
CONSENT_ITEM_STATE.ACCEPTED,
testStr,
constructMetadata(CONSENT_STRING_TYPE.TCF_V1, '12345')
);
const value = await manager.getConsentInstanceInfo();
expect(value).to.deep.equal(
constructConsentInfo(
CONSENT_ITEM_STATE.ACCEPTED,
testStr,
constructMetadata(CONSENT_STRING_TYPE.TCF_V1, '12345'),
{'purpose-abc': PURPOSE_CONSENT_STATE.ACCEPTED}
)
);
});
});

describe('onConsentStateChange', () => {
Expand Down Expand Up @@ -497,38 +464,6 @@ describes.realWin('ConsentStateManager', {amp: 1}, (env) => {
expect(storageSetSpy).to.not.be.called;
expect(storageRemoveSpy).to.be.calledOnce;
});

it('remove consentInfo when consentStr length exceeds', function* () {
expectAsyncConsoleError(/Cannot store consent information/);
let testStr = 'a';
// Reserve 26 chars to metadata size `"m":{"cst":1,"ac":"12345"}`
// Reserve 36 chars to the storage key, `''` and `{}`
// Leaves CONSENT_STORAGE_MAX - 62 chars to consent string
for (let i = 0; i < CONSENT_STORAGE_MAX - 62; i++) {
testStr += 'a';
}
instance.update(
CONSENT_ITEM_STATE.ACCEPTED,
testStr,
undefined,
constructMetadata(CONSENT_STRING_TYPE.TCF_V1, '12345')
);
yield macroTask();
expect(storageSetSpy).to.not.be.called;
expect(storageRemoveSpy).to.be.calledOnce;
});

it('allows large consentInfo when not using viewer storage API', async () => {
usesViewer = false;
let testStr = 'a';
for (let i = 0; i < CONSENT_STORAGE_MAX - 62; i++) {
testStr += 'a';
}
instance.update(CONSENT_ITEM_STATE.ACCEPTED, testStr);
await macroTask();
expect(storageSetSpy).to.be.calledOnce;
expect(storageRemoveSpy).to.not.be.called;
});
});

describe('should override stored value correctly', () => {
Expand Down
2 changes: 0 additions & 2 deletions extensions/amp-consent/integrating-consent.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ To add your consent management service to AMP runtime, it is expected that you:
- Meet the restrictions that the AMP runtime applies to ensure a good user experience. These includes
- Enforce the size of the consent prompt. The only two allowed sizes are the initial size (`width: 100vw`, `height: 30vh`), and the full screen size (`width: 100vw`, `height: 100%`) after user interactions.
- A default placeholder will be displayed before the consent prompt iframe is ready.
- Enforce the size of the stored consent information, when the page is served from a cache that supports the [Storage API](./../../spec/amp-localstorage.md#Storage-API). 1200 character length including storage key, consent string and additional metadata is the limit. Please [file an issue](https://github.com/ampproject/amphtml/issues/new) if you find that not sufficient.
- NOTE: You can detect if the page is being served from the origin from the `checkConsentHref` request header or via `window.location.ancestorOrigin` within the iframe. Additionally, if the page is served from the cache, there is no guarantee that the LocalStorage API is supported by the viewer, and the consent information might not be persisted.
- Understand that including `<amp-consent type='yourName'></amp-consent>` on the page won't block any components by default. **Please make sure to inform your service users to block AMP components either by the `<meta name="amp-consent-blocking">` metaTag, or the `data-block-on-consent` attribute.**
- Understand that AMP Consent doesn't attempt to interpret the consent info string from the CMP. Vendors can access the consent info string from CMPs via [provided APIs](https://github.com/ampproject/amphtml/blob/main/ads/README.md#amp-consent-integration). It's up to the CMP and service provider vendors to agree on the format of the consent info string.
- Create an [Intent-To-Implement issue](../../CONTRIBUTING.md#contributing-features) stating that you'll be adding support to your CMP service to AMP. A great start point is to follow the `_ping_` CMP service implementation that the AMP team creates for testing purpose.
Expand Down