Skip to content

Commit e395c00

Browse files
Move docs from Asana (#1792)
* Add in basic docs refactor * Add cursor rules files * Add breakage advice * Add in asana docs * Add architecture diagram * Prettier the docs output * Neaten * Docs fix * Update paths * Update owners for docs
1 parent 250f95f commit e395c00

14 files changed

+510
-230
lines changed

.cursorrules

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Content Scope Scripts - Cursor Rules
2+
3+
## Documentation References
4+
5+
When asked about Content Scope Scripts topics, refer to these documentation files:
6+
7+
- **API Reference**: `injected/docs/api-reference.md`
8+
- **Feature Development**: `injected/docs/features-guide.md`
9+
- **Platform Integration**: `injected/docs/platform-integration.md`
10+
- **Development Utilities**: `injected/docs/development-utilities.md`
11+
- **Testing**: `injected/docs/testing-guide.md`
12+
- **Favicon**: `injected/docs/favicon.md`
13+
- **Message Bridge**: `injected/docs/message-bridge.md`
14+
- **Documentation Index**: `injected/docs/README.md`
15+
- **High-level Overview**: `injected/README.md`

.prettierignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
build/**/*
22
docs/**/*
3+
!injected/docs/**/*
34
injected/src/types
45
special-pages/pages/**/types
56
injected/integration-test/extension/contentScope.js
67
injected/src/features/Scriptlets
78
**/*.json
89
**/*.md
10+
!injected/docs/**/*.md
911
**/*.html
1012
**/*.har
1113
**/*.css

CODEOWNERS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
* @duckduckgo/content-scope-scripts-owners
22

3+
# Documentation - anyone can edit
4+
injected/docs/ *
5+
36
# Feature owners
47
injected/src/features/fingerprinting-* @duckduckgo/content-scope-scripts-owners @jonathanKingston @englehardt
58
injected/src/canvas.js @duckduckgo/content-scope-scripts-owners @jonathanKingston @englehardt

injected/README.md

Lines changed: 58 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -1,202 +1,76 @@
1-
# Content scope scripts
2-
3-
Content Scope Scripts handles injecting in DOM modifications in a browser context; it's a cross platform solution that requires some minimal platform hooks.
4-
5-
## Content Scope Features API
6-
7-
Each platform calls into the API exposed by content-scope-features.js where the relevant JavaScript file is included from features/. This file loads the relevant platform enabled features. The platform itself should adhere to the features lifecycle when implementing.
8-
9-
The exposed API is a global called contentScopeFeatures and has three methods:
10-
- load
11-
- Calls the load method on all the features
12-
- init
13-
- Calls the init method on all the features
14-
- This should be passed the arguments object which has the following keys:
15-
- 'platform' which is an object with:
16-
- 'name' which is a string of 'android', 'ios', 'macos' or 'extension'
17-
- 'debug' true if debugging should be enabled
18-
- 'globalPrivacyControlValue' false if the user has disabled GPC.
19-
- 'sessionKey' a unique session based key.
20-
- 'cookie' TODO
21-
- 'site' which is an object with:
22-
- 'isBroken' true if remote config has an exception.
23-
- 'allowlisted' true if the user has disabled protections.
24-
- 'domain' the hostname of the site in the URL bar
25-
- 'enabledFeatures' this is an array of features/ to enable
26-
- urlChanged
27-
- Called when the top frame URL is changed (for Single Page Apps)
28-
- Also ensures that path changes for config 'conditional matching' are applied.
29-
- update
30-
- Calls the update method on all the features
31-
32-
## Features
33-
34-
These files stored in the features directory must include an init function and optionally update and load explained in the features lifecycle.
35-
36-
### `ConfigFeature` class
37-
The [ConfigFeature](https://github.com/duckduckgo/content-scope-scripts/blob/main/injected/src/config-feature.js) class is extended by each feature to implement remote config handling. It provides the following methods:
38-
39-
`getFeatureSettingEnabled`
40-
- For simple boolean settings, return true if the setting is 'enabled'
41-
42-
`getFeatureSetting`
43-
- Return a specific setting from the feature settings
44-
45-
`recomputeSiteObject`
46-
- Recomputes the site object for the feature, e.g when the URL has changed.
47-
48-
`ConfigFeature` class is also exportable and can be used by other scripts to build C-S-S like features that can handle remote configuration - currently used in [autofill.js](https://github.com/duckduckgo/duckduckgo-autofill/blob/main/src/site-specific-feature.js) to handle site specific autofill rules.
49-
50-
## Features Lifecycle
51-
52-
There are three stages that the content scope code is hooked into the platform:
53-
- `load`
54-
- This should be reserved for work that should happen that could cause a delay in loading the feature.
55-
- Given the current limitations of how we inject our code we don't have the Privacy Remote Configuration exceptions so authors should be wary of actually loading anything that would modify the page (and potentially breaking it).
56-
- This limitation may be re-addressed in manifest v3
57-
- One exception here is the first party cookie protections that are triggered on init to prevent race conditions.
58-
- `init`
59-
- This is the main place that features are actually loaded into the extension.
60-
- `update`
61-
- This allows the feature to be sent updates from the browser.
62-
- If this is triggered before init, these updates will be queued and triggered straight after.
63-
64-
### Platform specific integration details
65-
66-
The [injected/entry-points/](https://github.com/duckduckgo/content-scope-scripts/tree/main/injected/entry-points) directory handles platform specific differences and is glue code into calling the contentScopeFeatures API.
67-
68-
- In Firefox the code is loaded as a standard extension content script.
69-
- For Apple, Windows and Android the code is a UserScript that has some string replacements for properties and loads in as the page scope.
70-
- Note: currently we don't implement the update calls as it's only required by cookie protections which we don't implement.
71-
- All other browsers the code is stringified, base64 encoded and injected in as a self deleting `<script>` tag.
72-
73-
In the built output you will see these dramatic differences in the bundled code which is created into: /build
74-
75-
#### App specific integration replacements
76-
77-
- `$CONTENT_SCOPE$` - raw remote config object
78-
- `$USER_UNPROTECTED_DOMAINS$` - an array of user allowlisted domains
79-
- `$USER_PREFERENCES$` - an object containing:
80-
- platform: `{ name: '<ios | macos | extension | android>' }`
81-
- debug: boolean
82-
- globalPrivacyControlValue: boolean
83-
- sessionKey: `<CSRNG UUID 4 string>` (used for fingerprinting) - this should regenerate on browser close or every 24 hours.
84-
85-
### Features scope injection utilities
86-
87-
To handle the difference in scope injection we expose multiple utilities which behave differently per browser in src/utils.js and `ContentFeature` base class. for Firefox the code exposed handles [xrays correctly](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Sharing_objects_with_page_scripts) without needing the features to be authored differently.
88-
89-
- `ContentFeature.defineProperty()`
90-
- `defineProperty(object, propertyName, descriptor)` behaves the same as `Object.defineProperty(object, propertyName, descriptor)`
91-
- The difference is for Firefox we export the relevant functions so it can go across the xray
92-
- Use this method if `Object.getOwnPropertyDescriptors(object).propertyName` should to exist in the supporting browser.
93-
- `ContentFeature.wrapProperty(object, propertyName, descriptor)`
94-
- A simple wrapper around `defineProperty()` that ignores non-existing properties and retains unspecified descriptor keys.
95-
- Example usage: `this.wrapProperty('Navigator.prototype.userAgent', { get: () => 'fakeUA' })`
96-
- `ContentFeature.wrapMethod(object, propertyName, wrapperFn)`
97-
- Overrides a native method. wrapperFn() will be called in place of the original method. The original method will be passed as the first argument.
98-
- Example usage:
99-
```JavaScript
100-
this.wrapMethod(Permissions.prototype, 'query', async function (originalFn, queryObject) {
101-
if (queryObject.name === 'blocked-permission') {
102-
return {
103-
name: queryObject.name,
104-
state: 'denied',
105-
status: 'denied'
106-
}
107-
}
108-
return await nativeImpl.call(this, queryObject)
109-
})
110-
```
111-
- `ContentFeature.shimInterface(interfaceName, ImplClass, options)`
112-
- API for shimming standard constructors. See the WebCompat feature and JSDoc for more details.
113-
- Example usage:
114-
```javascript
115-
this.shimInterface('MediaSession', MyMediaSessionClass, {
116-
disallowConstructor: true,
117-
allowConstructorCall: false,
118-
wrapToString: true
119-
})
120-
```
121-
- `ContentFeature.shimProperty(instanceHost, instanceProp, implInstance, readOnly = false)`
122-
- API for shimming standard global objects. Usually you want to call `shimInterface()` first, and pass an object instance as `implInstance`. See the WebCompat feature and JSDoc for more details.
123-
- Example usage:
124-
```javascript
125-
this.shimProperty(Navigator.prototype, 'mediaSession', myMediaSessionInstance, true)
126-
```
127-
128-
- `DDGProxy`
129-
- Behaves a lot like `new window.Proxy` with a few differences:
130-
- has an `overload` method to actually apply the function to the native property.
131-
- Stores the native original property in _native such that it can be called elsewhere if needed without going through the proxy.
132-
- Triggers `addDebugFlag` if get/apply is called.
133-
- Sends debugging messaging if debug is enabled.
134-
- Allows for remotely disabling the override based on script URL via `shouldExemptMethod`.
135-
- Fixes `value.toString()` to appear like it was defined natively.
136-
- Example usage:
137-
```JavaScript
138-
const historyMethodProxy = new DDGProxy(this, History.prototype, 'pushState', {
139-
apply (target, thisArg, args) {
140-
applyRules(activeRules)
141-
return DDGReflect.apply(target, thisArg, args)
142-
}
143-
})
144-
historyMethodProxy.overload()
145-
```
146-
- `DDGReflect`
147-
- Calls into wrappedJSObject.Reflect for Firefox but otherwise exactly the same as [window.Reflect](Sources/BrowserServicesKit/UserScript/ContentScopeUserScript.swift)
148-
149-
### Testing Locally
150-
151-
Depending on what you are changing, you may need to run the build processes locally, or individual tests.
152-
The following all run within GitHub Actions when you create a pull request, but you can run them locally as well.
153-
154-
- eslint
155-
- Typescript
156-
- Unit tests (jasmine)
157-
- Feature Integration Tests (playwright)
158-
- Feature Build process
159-
160-
If you want to get a good feeling for whether a PR or CI run will pass/fail, you can run the `test` command
161-
which chains most of the following together
1+
# Content Scope Scripts
1622

163-
```shell
164-
# run this if you want some confidence that your PR will pass
165-
npm test
166-
```
3+
Content Scope Scripts handles injecting DOM modifications in a browser context; it's a cross-platform solution that requires some minimal platform hooks.
4+
5+
## Quick Start
6+
7+
Content Scope Scripts provides a unified API for browser privacy features across multiple platforms (Firefox, Chrome, Safari, Android, iOS). Features are loaded dynamically based on remote configuration and can be enabled/disabled per site.
8+
9+
## Documentation
10+
11+
📚 **Detailed documentation is available in the [docs](./docs/) directory:**
12+
13+
- **[API Reference](./docs/api-reference.md)** - Complete reference for the Content Scope Features API
14+
- **[Features Guide](./docs/features-guide.md)** - How to develop features and understand the feature lifecycle
15+
- **[Platform Integration](./docs/platform-integration.md)** - Platform-specific implementation details
16+
- **[Development Utilities](./docs/development-utilities.md)** - Scope injection utilities and development tools
17+
- **[Testing Guide](./docs/testing-guide.md)** - Local testing and development workflow
18+
19+
## Key Concepts
16720

168-
#### eslint
21+
### Features
22+
Features are JavaScript modules that implement privacy protections. Each feature:
23+
- Extends the `ConfigFeature` class for remote configuration support
24+
- Implements the feature lifecycle (`load`, `init`, `update`)
25+
- Can be enabled/disabled per site via remote configuration
16926

170-
See root-level package for lint commands
27+
### Platform Support
28+
- **Firefox**: Standard extension content scripts
29+
- **Apple/Android**: UserScripts with string replacements
30+
- **Other browsers**: Base64-encoded script injection
17131

172-
#### Typescript
32+
### API
33+
The global `contentScopeFeatures` object provides:
34+
- `load()` - Initialize features that may cause loading delays
35+
- `init(args)` - Main feature initialization with platform/site configuration
36+
- `urlChanged()` - Handle Single Page App navigation
37+
- `update()` - Receive browser updates
17338

174-
See root-level package for Typescript commands
39+
---
17540

176-
#### Unit Tests (jasmine)
41+
## Architecture Overview
17742

178-
Everything for unit-testing is located in the `unit-test` folder. Jasmine configuration is in `unit-test/jasmine.json`.
43+
![Content Scope Scripts architecture diagram](./docs/img/feature-explanation.png)
17944

45+
*High-level overview of how Content Scope Scripts are built and integrated into platforms (example: macOS).*
46+
47+
## Development
48+
49+
### Quick Test
18050
```shell
181-
npm run test-unit
51+
npm test
18252
```
18353

184-
#### Feature Integration Tests (playwright)
185-
Everything within `integration-test` is integration tests controlled by Playwright.
186-
54+
### Individual Commands
18755
```shell
188-
npm run test-int
56+
npm run test-unit # Unit tests (Jasmine)
57+
npm run test-int # Integration tests (Playwright)
58+
npm run build # Build platform-specific artifacts
18959
```
19060

191-
#### Feature Build process
61+
### Project Structure
62+
- `src/features/` - Feature implementations
63+
- `entry-points/` - Platform-specific entry points
64+
- `unit-test/` - Unit test suite
65+
- `integration-test/` - Integration test suite
19266

193-
To produce all artefacts that are used by platforms, just run the `npm run build` command.
194-
This will create platform specific code within the `build` folder (that is not checked in)
67+
## Third-Party Libraries
68+
- [Adguard Scriptlets](https://github.com/AdguardTeam/Scriptlets)
19569

196-
```shell
197-
npm run build
198-
```
70+
---
19971

200-
#### Third-Party Libraries
72+
## Third-Party Libraries
20173
We make use of the following submodules:
202-
- [Adguard Scriptlets](https://github.com/AdguardTeam/Scriptlets)
74+
- [Adguard Scriptlets](https://github.com/AdguardTeam/Scriptlets)
75+
76+
For detailed information about any specific topic, please refer to the [documentation](./docs/).

injected/docs/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# Content Scope Scripts Documentation
2+
3+
This directory contains detailed documentation for the Content Scope Scripts project.
4+
5+
## Documentation Index
6+
7+
### Core Documentation
8+
9+
- **[API Reference](./api-reference.md)** - Complete reference for the Content Scope Features API
10+
- **[Features Guide](./features-guide.md)** - How to develop features and understand the feature lifecycle
11+
- **[Platform Integration](./platform-integration.md)** - Platform-specific implementation details and integration patterns
12+
13+
### Development Resources
14+
15+
- **[Development Utilities](./development-utilities.md)** - Scope injection utilities and development tools
16+
- **[Testing Guide](./testing-guide.md)** - Local testing and development workflow
17+
18+
### Existing Documentation
19+
20+
- **[Favicon](./favicon.md)** - Favicon-related documentation
21+
- **[Message Bridge](./message-bridge.md)** - Message bridge implementation details
22+
23+
## Getting Started
24+
25+
If you're new to Content Scope Scripts, start with the main [README](../README.md) for a high-level overview, then dive into the specific documentation based on your needs:
26+
27+
- **Building features?**[Features Guide](./features-guide.md)
28+
- **Integrating with a platform?**[Platform Integration](./platform-integration.md)
29+
- **Using the API?**[API Reference](./api-reference.md)
30+
- **Developing utilities?**[Development Utilities](./development-utilities.md)
31+
- **Testing your changes?**[Testing Guide](./testing-guide.md)

injected/docs/api-reference.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Content Scope Features API Reference
2+
3+
Each platform calls into the API exposed by [content-scope-features.js](../src/content-scope-features.js) where the relevant JavaScript file is included from `features/`. This file loads the relevant platform enabled features. The platform itself should adhere to the features lifecycle when implementing.
4+
5+
## Global API: `contentScopeFeatures`
6+
7+
The exposed API is a global called `contentScopeFeatures` and has three methods:
8+
9+
### `load()`
10+
11+
Calls the load method on all the features
12+
13+
### `init(arguments)`
14+
15+
Calls the init method on all the features. This should be passed the arguments object which has the following keys:
16+
17+
- **`platform`** - An object with:
18+
- `name` - A string of 'android', 'ios', 'macos' or 'extension'
19+
- **`debug`** - `true` if debugging should be enabled
20+
- **`globalPrivacyControlValue`** - `false` if the user has disabled GPC
21+
- **`sessionKey`** - A unique session based key
22+
- **`cookie`** - TODO
23+
- **`site`** - An object with:
24+
- `isBroken` - `true` if remote config has an exception
25+
- `allowlisted` - `true` if the user has disabled protections
26+
- `domain` - The hostname of the site in the URL bar
27+
- `enabledFeatures` - An array of features to enable
28+
29+
### `urlChanged()`
30+
31+
Called when the top frame URL is changed (for Single Page Apps). Also ensures that path changes for config 'conditional matching' are applied.
32+
33+
### `update()`
34+
35+
Calls the update method on all the features

0 commit comments

Comments
 (0)