Skip to content

Commit

Permalink
Impelemnt event filtering based on a list of allowed origins (#53)
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastienbarbier committed May 6, 2020
1 parent b660a2d commit 8eac668
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.3.0] - 2020-05-06

### Added

- `setAllowedOrigins()` method now allows to filter events based on its origin.

## [1.2.8] - 2020-04-22

### Added
Expand Down
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,9 @@
- [Unsubscribing from event](#unsubscribing-from-event)
- [Reactive approach to subscribe for shell host events](#reactive-approach-to-subscribe-for-shell-host-events)
- [Debugging postMessage API events](#debugging-postmessage-api-events)


- [Security](#security)
- [Support](#support)
- [License](#license)

### SHELL-SDK Version1 events

Expand Down Expand Up @@ -367,6 +368,24 @@ window.fsmShellMessageLogger.filterTable({
})
```

## Security

### Allowed origins only

You can use the method `.setAllowedOrigins` to restrict message handling to a list of allowed origins.

```javascript
sdk = ShellSdk.init();
sdk.setAllowedOrigins([
'example.com',
'example2.com'
]);
```

To help debugging, an error will be displayed if an event come from an other origin.

You disable this settings, call `.setAllowedOrigins` with an empy parameter.

## Support

In case you need further help, check out the [SAP Field Service Management Help Portal](https://docs.coresystems.net/) or report and incident in [SAP Support Portal](https://support.sap.com) with the component "CEC-SRV-FSM".
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fsm-shell",
"version": "1.2.8",
"version": "1.3.0",
"description": "client library for FSM shell",
"main": "release/fsm-shell-client.js",
"module": "release/fsm-shell-client.es.js",
Expand Down
61 changes: 61 additions & 0 deletions src/ShellSdk.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,65 @@ describe('Shell Sdk', () => {
expect(onViewStateServiceCall.calledBefore(postMessageParent)).toBe(true);
});

it('should only accept events from allowedOrigins', () => {
const postMessageParent = sinon.spy();
sdk = ShellSdk.init({
postMessage: postMessageParent
} as any as Window, sdkOrigin, windowMock);

sdk.setAllowedOrigins([
'https://s1.exemple.com',
'https://s2.exemple.com'
]);

const data = {
type: SHELL_EVENTS.Version1.REQUIRE_CONTEXT,
value: {
message: 'test data'
}
};

const requestContext = sinon.spy();

sdk.on(SHELL_EVENTS.Version1.REQUIRE_CONTEXT, requestContext);

windowMockCallback({ origin: 'localhost:8000', data });
expect(requestContext.called).toBe(false);
requestContext.resetHistory();

windowMockCallback({ origin: 'https://s1.exemple.com', data });
expect(requestContext.called).toBe(true);
requestContext.resetHistory();

windowMockCallback({ origin: 's1.exemple.com', data });
expect(requestContext.called).toBe(false);
requestContext.resetHistory();

windowMockCallback({ origin: 'https://s3.exemple.com', data });
expect(requestContext.called).toBe(false);
requestContext.resetHistory();

// Test reseting a list
sdk.setAllowedOrigins('*');
windowMockCallback({ origin: 'localhost:8000', data });
expect(requestContext.called).toBe(true);
requestContext.resetHistory();

sdk.setAllowedOrigins(['https://s1.exemple.com']);
windowMockCallback({ origin: 'https://s3.exemple.com', data });
expect(requestContext.called).toBe(false);
sdk.setAllowedOrigins();
windowMockCallback({ origin: 'https://s3.exemple.com', data });
expect(requestContext.called).toBe(true);
requestContext.resetHistory();

sdk.setAllowedOrigins(['https://s1.exemple.com']);
windowMockCallback({ origin: 'https://s3.exemple.com', data });
expect(requestContext.called).toBe(false);
sdk.setAllowedOrigins([]);
windowMockCallback({ origin: 'https://s3.exemple.com', data });
expect(requestContext.called).toBe(true);
requestContext.resetHistory();
});

});
11 changes: 11 additions & 0 deletions src/ShellSdk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ export class ShellSdk {
private debugger: Debugger;
private outletsMap: Map<HTMLIFrameElement, string>;

private allowedOrigins: string[] = [];

private constructor(
private target: Window,
private origin: string,
Expand Down Expand Up @@ -59,6 +61,10 @@ export class ShellSdk {
return window.self !== window.top;
}

public setAllowedOrigins(allowedOrigins: string[] | '*' = []) {
this.allowedOrigins = allowedOrigins === '*' ? [] : allowedOrigins;
}

// Called by outlet component to assign an generated uuid to an iframe. This is key
// to allow one to one communication between a pluging and shell-host
public registerOutlet(frame: HTMLIFrameElement) {
Expand Down Expand Up @@ -172,6 +178,11 @@ export class ShellSdk {
return;
}

if (this.allowedOrigins && Array.isArray(this.allowedOrigins) && this.allowedOrigins.length != 0 && this.allowedOrigins.indexOf(event.origin) === -1) {
console.error(`${event.origin} is not in the list of known origins`);
return;
}

const payload = event.data as { type: EventType, value: any, from?: string[], to?: string[] };

// we ignore LOADING SUCCESS as it is handled by the outlet component itself
Expand Down

0 comments on commit 8eac668

Please sign in to comment.