├── .eslintignore
├── karma-tests
├── components
│ ├── actors-panel-spec.js
│ ├── packets-panel-spec.js
│ ├── packets-sidebar-spec.js
│ ├── main-tabbed-area-spec.js
│ ├── packets-toolbar-spec.js
│ └── packet-spec.js
├── .eslintrc
├── custom-react-matchers.js
├── lib
│ └── firebug-sdk-shims.js
└── test-main.js
├── data
├── inspector
│ ├── res
│ │ ├── icon-16.png
│ │ ├── sent-arrow.png
│ │ ├── received-arrow.png
│ │ ├── sent-arrow-selected.png
│ │ ├── received-arrow-selected.png
│ │ └── arrow.svg
│ ├── actions
│ │ ├── index.js
│ │ ├── global.js
│ │ ├── actors.js
│ │ └── packets.js
│ ├── css
│ │ ├── base.css
│ │ ├── actors-panel.css
│ │ ├── search-box.css
│ │ ├── toolbar.css
│ │ ├── tree-editor-view.css
│ │ ├── toolbox.css
│ │ └── packets-panel.css
│ ├── store.js
│ ├── reducers
│ │ ├── index.js
│ │ ├── global.js
│ │ ├── actors.js
│ │ └── packets.js
│ ├── search.js
│ ├── config.js
│ ├── containers
│ │ └── app.js
│ ├── components
│ │ ├── text-with-tooltip.js
│ │ ├── packets-message.js
│ │ ├── packet-details.js
│ │ ├── packets-limit.js
│ │ ├── actors-toolbar.js
│ │ ├── search-box.js
│ │ ├── packet-stack-sidepanel.js
│ │ ├── packets-panel.js
│ │ ├── packets-sidebar.js
│ │ ├── packets-summary.js
│ │ ├── packet-list.js
│ │ ├── main-tabbed-area.js
│ │ ├── factories.js
│ │ ├── pools.js
│ │ ├── packets-toolbar.js
│ │ ├── packet-editor.js
│ │ ├── stack-frame-rep.js
│ │ ├── packet.js
│ │ └── actors-panel.js
│ ├── main.html
│ ├── main.js
│ └── frame-script.js
├── lib
│ ├── bootstrap
│ │ └── fonts
│ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ └── glyphicons-halflings-regular.woff2
│ └── react
│ │ └── react-dom.js
├── shared
│ ├── react-bootstrap-factories.js
│ ├── react-helpers.js
│ ├── resizer.js
│ └── rdp-inspector-window.js
├── connection-list
│ ├── css
│ │ └── connection-list.css
│ ├── actions.js
│ ├── store.js
│ ├── reducers.js
│ ├── config.js
│ ├── containers
│ │ └── main-panel.js
│ ├── index.html
│ ├── index.js
│ └── components
│ │ └── connection-list.js
└── .eslintrc
├── .jshintrc
├── chrome
├── skin
│ └── classic
│ │ └── shared
│ │ ├── icon16.png
│ │ ├── icon32.png
│ │ ├── icon64.png
│ │ └── search.svg
├── icons
│ └── default
│ │ └── rdpinspectorconsole.ico
├── locale
│ ├── en-US
│ │ ├── connections.properties
│ │ ├── toolbox.properties
│ │ └── inspector.properties
│ ├── zh-CN
│ │ ├── toolbox.properties
│ │ └── inspector.properties
│ ├── nl
│ │ ├── toolbox.properties
│ │ └── inspector.properties
│ └── pt-BR
│ │ ├── toolbox.properties
│ │ └── inspector.properties
└── content
│ ├── connections-window.xul
│ └── inspector-window.xul
├── test
├── .eslintrc
└── test-inspector-service.js
├── lib
├── .eslintrc
├── inspector-front.js
├── main.js
├── webide-connections-monitor.js
├── transport-observer.js
├── toolbox-overlay.js
├── connection-list-window.js
├── inspector-actor.js
└── start-button.js
├── .jpmignore
├── .eslintrc
├── .gitignore
├── chrome.manifest
├── README.md
├── .travis.yml
├── index.js
├── karma.conf.js
└── package.json
/.eslintignore:
--------------------------------------------------------------------------------
1 | coverage/
2 | data/lib/
3 | karma-tests/lib/
4 |
--------------------------------------------------------------------------------
/karma-tests/components/actors-panel-spec.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
--------------------------------------------------------------------------------
/data/inspector/res/icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/inspector/res/icon-16.png
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | "esnext": "true",
3 | "predef": [ "require", "exports", "module" ],
4 | "curly": "true"
5 | }
6 |
--------------------------------------------------------------------------------
/data/inspector/res/sent-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/inspector/res/sent-arrow.png
--------------------------------------------------------------------------------
/chrome/skin/classic/shared/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/chrome/skin/classic/shared/icon16.png
--------------------------------------------------------------------------------
/chrome/skin/classic/shared/icon32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/chrome/skin/classic/shared/icon32.png
--------------------------------------------------------------------------------
/chrome/skin/classic/shared/icon64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/chrome/skin/classic/shared/icon64.png
--------------------------------------------------------------------------------
/data/inspector/res/received-arrow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/inspector/res/received-arrow.png
--------------------------------------------------------------------------------
/test/.eslintrc:
--------------------------------------------------------------------------------
1 | // extends common eslintrc config with addon-sdk specific configs
2 | {
3 | "extends": "../lib/.eslintrc"
4 | }
5 |
--------------------------------------------------------------------------------
/data/inspector/res/sent-arrow-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/inspector/res/sent-arrow-selected.png
--------------------------------------------------------------------------------
/chrome/icons/default/rdpinspectorconsole.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/chrome/icons/default/rdpinspectorconsole.ico
--------------------------------------------------------------------------------
/data/inspector/res/received-arrow-selected.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/inspector/res/received-arrow-selected.png
--------------------------------------------------------------------------------
/data/lib/bootstrap/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/lib/bootstrap/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/data/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/data/lib/bootstrap/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/lib/bootstrap/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/data/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/firebug/rdp-inspector/HEAD/data/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/karma-tests/.eslintrc:
--------------------------------------------------------------------------------
1 | // extends data eslintrc config with karma tests specific configs
2 | {
3 | "extends": "../data/.eslintrc",
4 | "env": {},
5 | "rules": {},
6 | "globals": {}
7 | }
8 |
--------------------------------------------------------------------------------
/chrome/locale/en-US/connections.properties:
--------------------------------------------------------------------------------
1 | # LOCALIZATION NOTE (rdpConnections.tab.LocalTabs, rdpConnections.tab.WebIDE)
2 | # A label for "Connect To..." window tabs.
3 | rdpConnections.tab.LocalTabs=Local Tabs
4 | rdpConnections.tab.WebIDE=WebIDE
5 |
--------------------------------------------------------------------------------
/data/shared/react-bootstrap-factories.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | const ReactBootstrap = require("react-bootstrap");
8 | const { ReactLazyFactories } = require("shared/react-helpers");
9 |
10 | module.exports = ReactLazyFactories(ReactBootstrap);
11 |
12 | });
13 |
--------------------------------------------------------------------------------
/data/connection-list/css/connection-list.css:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /******************************************************************************/
4 | /* Connection List Window */
5 |
6 | .tab-content .list-group-item {
7 | border-radius: 0;
8 | }
9 |
10 | .tab-content .list-group-item:first-child {
11 | border-top: 0;
12 | }
13 |
--------------------------------------------------------------------------------
/data/inspector/actions/index.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | const global = require("./global");
8 | const actors = require("./actors");
9 | const packets = require("./packets");
10 |
11 | module.exports = Object.assign({}, global, actors, packets, {
12 | types: Object.assign({}, actors.types, packets.types)
13 | });
14 |
15 | });
16 |
--------------------------------------------------------------------------------
/data/connection-list/actions.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | const types = {
8 | SET_CONNECTIONS: "SET_CONNECTIONS"
9 | };
10 |
11 | // export actions types and action creators
12 | module.exports = {
13 | types,
14 |
15 | setConnections(connections) {
16 | return { type: types.SET_CONNECTIONS, connections };
17 | }
18 | };
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/data/inspector/actions/global.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | const types = {
8 | SET_SEARCH_FILTER: "SET_SEARCH_FILTER",
9 | };
10 |
11 | // export actions types and action creators
12 | module.exports = {
13 | types,
14 |
15 | setSearchFilter(filter) {
16 | return { type: types.SET_SEARCH_FILTER, filter };
17 | },
18 | };
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/lib/.eslintrc:
--------------------------------------------------------------------------------
1 | // extends common eslintrc config with addon-sdk specific configs
2 | {
3 | "extends": "../.eslintrc",
4 | "env": {
5 | // commonjs conventions
6 | "node": true
7 | },
8 | "rules": {
9 | "global-strict": 0,
10 | "dot-notation": 0,
11 | "new-cap": 0,
12 | "no-underscore-dangle": 0
13 | },
14 | "globals": {
15 | // firebug.sdk globals
16 | "FBTrace": true
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/.jpmignore:
--------------------------------------------------------------------------------
1 | # Doc Files
2 | /docs/
3 | README.md
4 |
5 | # Test Files
6 | /test/
7 |
8 | karma.conf.js
9 | /karma-tests/
10 |
11 | # GIT
12 | /.git/
13 |
14 | # exclude hidden files
15 | .*
16 |
17 | # Existing packages
18 | *.xpi
19 |
20 | # npm debug log file
21 | npm-debug.log
22 |
23 | # Excludes npm devDependecies
24 | /node_modules/
25 |
26 | # Includes firebug.sdk
27 | !/node_modules/firebug.sdk
28 |
29 | # Code Coverage logs & reports
30 | /coverage/
31 |
--------------------------------------------------------------------------------
/data/inspector/css/base.css:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /******************************************************************************/
4 | /* General */
5 |
6 | body {
7 | background-color: white;
8 | padding: 0;
9 | margin: 0;
10 | height: 100%;
11 | }
12 |
13 | *:focus {
14 | outline: none !important;
15 | }
16 |
17 | #content {
18 | height: 100%;
19 | }
20 |
21 | #content > DIV {
22 | height: 100%;
23 | }
24 |
--------------------------------------------------------------------------------
/data/connection-list/store.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Redux
8 | const { createStore } = require("redux");
9 |
10 | // RDP Inspector
11 | const { rootReducer } = require("./reducers");
12 |
13 | function configureStore(initialState) {
14 | return createStore(rootReducer, initialState);
15 | }
16 |
17 | // Exports from this module
18 | exports.configureStore = configureStore;
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/data/inspector/store.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Redux
8 | const { createStore } = require("redux");
9 |
10 | // RDP Inspector
11 | const { rootReducer } = require("./reducers/index");
12 |
13 | function configureStore(initialState) {
14 | return createStore(rootReducer, initialState);
15 | }
16 |
17 | // Exports from this module
18 | exports.configureStore = configureStore;
19 |
20 | });
21 |
--------------------------------------------------------------------------------
/data/inspector/reducers/index.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Redux
8 | const { combineReducers } = require("redux");
9 |
10 | // RDP Inspector
11 | const global = require("./global");
12 | const actors = require("./actors");
13 | const packets = require("./packets");
14 |
15 | var rootReducer = combineReducers({ global, actors, packets });
16 |
17 | // Exports from this module
18 | exports.rootReducer = rootReducer;
19 | });
20 |
--------------------------------------------------------------------------------
/data/inspector/actions/actors.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | const types = {
8 | SET_ACTORS: "SET_ACTORS",
9 | CLEAR_ACTORS: "CLEAR_ACTORS"
10 | };
11 |
12 | // export actions types and action creators
13 | module.exports = {
14 | types,
15 |
16 | setActors(actors) {
17 | return { type: types.SET_ACTORS, actors };
18 | },
19 |
20 | clearActors() {
21 | return { type: types.CLEAR_ACTORS };
22 | },
23 | };
24 |
25 | });
26 |
--------------------------------------------------------------------------------
/chrome/locale/zh-CN/toolbox.properties:
--------------------------------------------------------------------------------
1 | rdpInspector.title=RDP Inspector
2 | rdpInspector.startButton.title=RDP Inspector
3 | rdpInspector.startButton.tip=远程调试协议探查器。
4 | rdpInspector.menu.about.label=关于 RDP Inspector...
5 | rdpInspector.menu.about.tip=有关 RDP Inspector 的信息
6 | rdpInspector.menu.visitHomePage.label=访问主页...
7 | rdpInspector.menu.visitHomePage.tip=详细了解有关 RDP Inspector
8 | rdpInspector.menu.reportIssue.label=报告问题...
9 | rdpInspector.menu.reportIssue.tip=您遇到了 bug?或是有关于新功能的点子?告诉我们吧!
10 | rdpInspector.menu.group.label=讨论组...
11 | rdpInspector.menu.group.tip=打开讨论组网站 (与 Firebug 共享)
12 |
--------------------------------------------------------------------------------
/chrome/locale/zh-CN/inspector.properties:
--------------------------------------------------------------------------------
1 | rdpInspector.option.showInlineDetails=显示数据包的详细信息
2 | rdpInspector.option.hideInlineDetails=隐藏数据包的详细信息
3 | rdpInspector.option.cachePackets=在探查器打开前缓存数据包
4 | rdpInspector.cmd.clear=清空
5 | rdpInspector.cmd.find=查找
6 | rdpInspector.cmd.summary=摘要
7 | rdpInspector.tooltip.sizeSent=向调试器服务器发送数据的总量
8 | rdpInspector.tooltip.sizeReceived=从调试器服务器接收数据的总量
9 | rdpInspector.tooltip.packetsSent=向调试器服务器发送的数据包数量
10 | rdpInspector.tooltip.packetsReceived=从调试器服务器接收的数据包数量
11 | rdpInspector.label.packets=数据包
12 | rdpInspector.label.data=数据
13 | rdpInspector.cmd.refresh=刷新
14 |
--------------------------------------------------------------------------------
/data/inspector/css/actors-panel.css:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /******************************************************************************/
4 | /* Actors Panel */
5 |
6 | .poolContainer {
7 | font-size: 12px;
8 | }
9 |
10 | .poolTable {
11 | border: 1px solid rgb(221, 221, 221);
12 | width: 100%;
13 | margin-bottom: 10px;
14 | }
15 |
16 | .poolRow TD,
17 | .poolRow TH {
18 | border-bottom: 1px solid rgb(221, 221, 221);
19 | padding-left: 10px;
20 | }
21 |
22 | .poolTable.actorClass {
23 | background-color: rgb(247, 247, 247);
24 | }
25 |
--------------------------------------------------------------------------------
/data/inspector/css/search-box.css:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /******************************************************************************/
4 | /* Search Box */
5 |
6 | .searchBox {
7 | height: 21px;
8 | font-size: 12px;
9 | margin-top: 2px;
10 | border: 1px solid rgb(170, 188, 207);
11 | width: 200px;
12 | position: fixed; /* xxxHonza: how to avoid fixed position? */
13 | right: 5px;
14 | background-image: url("chrome://rdpinspector/skin/search.svg");
15 | background-repeat: no-repeat;
16 | background-position: 2px center;
17 | padding-left: 20px;
18 | }
19 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "indent": [2, 2], // check 2 space indentation
4 | "no-mixed-spaces-and-tabs": [2],
5 | "quotes": [2, "double"],
6 | "semi": [1, "always"],
7 |
8 | // disabled rule which enforce unix or windows line breaks
9 | "linebreak-style": [0],
10 |
11 | // disabled comma-dangle is safe for our use case
12 | "comma-dangle": [0],
13 |
14 | // disabled eqeqeq and no-use-before-define are safe if you use them correctly
15 | "eqeqeq": [0],
16 | "no-use-before-define": [0],
17 | },
18 | "env": {
19 | "es6": true
20 | },
21 | "globals": {
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/data/shared/react-helpers.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | const React = require("react");
8 |
9 | exports.ReactLazyFactories = (reactElementsSource) => {
10 | return new Proxy({}, {
11 | get(target, name) {
12 | if ( !(name in reactElementsSource) ) {
13 | throw Error(`ReactLazyFactories: ${name} not found`);
14 | }
15 |
16 | if ( !(name in target) ) {
17 | target[name] = React.createFactory(reactElementsSource[name]);
18 | }
19 |
20 | return target[name];
21 | }
22 | });
23 | };
24 |
25 | });
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Junk that could exist anywhere:
3 | .DS_Store
4 | *.swp
5 | *.tmp
6 | .*.gz
7 | *.patch
8 | *~
9 |
10 | # Temporary files created by Eclipse
11 | .tmp*
12 |
13 | # Editor junk
14 | *.project
15 | /.pydevproject
16 | /.settings/
17 | /.settings.xml
18 | /.settings.xml.old
19 | /.idea/
20 | *.iws
21 | *.ids
22 | *.iml
23 | *.ipr
24 |
25 | # Build Files
26 | /build/
27 | /release/
28 | *.graphml
29 | *.xpi
30 |
31 | # Files from NPM
32 | /node_modules/
33 |
34 | # Extensions
35 | /firebug@software.joehewitt.com
36 |
37 | # Bash
38 | *.sh
39 | *.bat
40 |
41 | # code coverage logs & reports
42 | /coverage/
43 |
44 | bootstrap.js
45 | install.rdf
46 | npm-debug.log
47 |
--------------------------------------------------------------------------------
/data/connection-list/reducers.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // actions types
8 | const { types } = require("./actions");
9 |
10 | /**
11 | * Initial state definition
12 | */
13 | const initialState = {};
14 |
15 | function connections(state = initialState, action) {
16 | switch(action.type) {
17 | case types.SET_CONNECTIONS:
18 | return action.connections;
19 | default:
20 | return state;
21 | }
22 | }
23 |
24 | // Export combined reducers
25 |
26 | // Redux
27 | const { combineReducers } = require("redux");
28 |
29 | exports.rootReducer = combineReducers({
30 | connections
31 | });
32 |
33 | });
34 |
--------------------------------------------------------------------------------
/data/inspector/reducers/global.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | // actions types
8 | const { types } = require("../actions/global");
9 |
10 | /**
11 | * Initial state definition
12 | */
13 | const initialState = {};
14 |
15 | function globalReducer(state = initialState, action) {
16 | switch(action.type) {
17 | case types.SET_SEARCH_FILTER:
18 | return setSearchFilter(state, action.filter);
19 | default:
20 | return state;
21 | }
22 | }
23 |
24 | module.exports = globalReducer;
25 |
26 |
27 | function setSearchFilter(state, filter) {
28 | return Object.assign({}, state, {
29 | searchFilter: filter
30 | });
31 | }
32 |
33 | });
34 |
--------------------------------------------------------------------------------
/chrome/locale/nl/toolbox.properties:
--------------------------------------------------------------------------------
1 | rdpInspector.title=RDP Inspector
2 | rdpInspector.startButton.title=RDP-inspecteur
3 | rdpInspector.startButton.tip=Protocolinspecteur voor foutopsporing op afstand.
4 | rdpInspector.menu.about.label=Over RDP Inspector…
5 | rdpInspector.menu.about.tip=Informatie over RDP Inspector
6 | rdpInspector.menu.visitHomePage.label=Startpagina bezoeken…
7 | rdpInspector.menu.visitHomePage.tip=Lees meer over RDP Inspector
8 | rdpInspector.menu.reportIssue.label=Probleem melden…
9 | rdpInspector.menu.reportIssue.tip=Hebt u een bug gevonden of zou u graag een nieuwe functie zien? Laat het ons weten!
10 | rdpInspector.menu.group.label=Discussiegroep…
11 | rdpInspector.menu.group.tip=De website van de discussiegroep (gedeeld met Firebug) openen
12 |
--------------------------------------------------------------------------------
/chrome/locale/pt-BR/toolbox.properties:
--------------------------------------------------------------------------------
1 | rdpInspector.title=RDP Inspector
2 | rdpInspector.startButton.title=RDP Inspector
3 | rdpInspector.startButton.tip=Inspetor de protocolo de depuração remota.
4 | rdpInspector.menu.about.label=Sobre o RDP Inspector
5 | rdpInspector.menu.about.tip=Informações sobre o RDP Inspector
6 | rdpInspector.menu.visitHomePage.label=Visite a Página Principal…
7 | rdpInspector.menu.visitHomePage.tip=Saiba mais sobre o RDP Inspector
8 | rdpInspector.menu.reportIssue.label=Relatório do problema…
9 | rdpInspector.menu.reportIssue.tip=Encontrou um bug ou precisa de um novo recurso? Nos informe!
10 | rdpInspector.menu.group.label=Grupo de discussão…
11 | rdpInspector.menu.group.tip=Abrir o site do grupo de discussão (compartilhado com o Firebug)
12 |
--------------------------------------------------------------------------------
/karma-tests/custom-react-matchers.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | var React = require("react");
8 | var { TestUtils } = React.addons;
9 |
10 | module.exports = {
11 | toBeFoundInReactTree: () => {
12 | return {
13 | compare: (component, tree, length) => {
14 | var message = "React Component '" + component.displayName + "'" +
15 | " not found in the rendered tree";
16 |
17 | var instances = TestUtils.scryRenderedComponentsWithType(tree, component);
18 |
19 | return {
20 | pass: length ?
21 | instances.length === length : instances.length > 0,
22 | message: message
23 | };
24 | }
25 | };
26 | }
27 | };
28 |
29 | });
30 |
--------------------------------------------------------------------------------
/chrome.manifest:
--------------------------------------------------------------------------------
1 | content rdpinspector chrome/content/
2 | skin rdpinspector classic/1.0 chrome/skin/classic/shared/
3 | skin rdpinspector-firebug.sdk classic/1.0 node_modules/firebug.sdk/skin/classic/shared/
4 |
5 | locale rdpinspector en-US chrome/locale/en-US/
6 | locale rdpinspector zh-CN chrome/locale/zh-CN/
7 | locale rdpinspector nl chrome/locale/nl/
8 | locale rdpinspector pt-BR chrome/locale/pt-BR/
9 |
10 | locale rdpinspector-firebug.sdk en-US node_modules/firebug.sdk/locale/en-US/
11 | locale rdpinspector-firebug.sdk zh-CN node_modules/firebug.sdk/locale/zh-CN/
12 | locale rdpinspector-firebug.sdk nl node_modules/firebug.sdk/locale/nl/
13 | locale rdpinspector-firebug.sdk pt-BR node_modules/firebug.sdk/locale/pt-BR/
14 |
--------------------------------------------------------------------------------
/data/inspector/search.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | const actions = require("./actions/index");
8 |
9 | /**
10 | * This object is responsible for listening search events
11 | * and updating application state (the root RJS component).
12 | */
13 | function Search(win, store) {
14 | this.win = win;
15 | this.store = store;
16 |
17 | this.win.addEventListener("search", this.onSearch.bind(this));
18 | }
19 |
20 | Search.prototype =
21 | /** @lends Search */
22 | {
23 | onSearch: function(event) {
24 | var value = event.data;
25 | this.store.dispatch(actions.setSearchFilter(value));
26 | }
27 | };
28 |
29 | // Exports from this module
30 | exports.Search = Search;
31 | });
32 |
--------------------------------------------------------------------------------
/chrome/locale/pt-BR/inspector.properties:
--------------------------------------------------------------------------------
1 | rdpInspector.option.showInlineDetails=Exibir detalhes do pacote
2 | rdpInspector.option.hideInlineDetails=Ocultar detalhes do pacote
3 | rdpInspector.option.cachePackets=Pacotes da cache antes do inspector ser aberto
4 | rdpInspector.cmd.clear=Limpar
5 | rdpInspector.cmd.find=Procurar
6 | rdpInspector.cmd.summary=Resumo
7 | rdpInspector.tooltip.sizeSent=A quantidade total de dados enviado para o servidor depurador
8 | rdpInspector.tooltip.sizeReceived=Quantidade total de dados recebidos do servidor depurador
9 | rdpInspector.tooltip.packetsSent=O número de pacotes enviada para o servidor depurador
10 | rdpInspector.tooltip.packetsReceived=Número de pacotes recebidos a partir do servidor depurador
11 | rdpInspector.label.packets=Pacotes
12 | rdpInspector.label.data=Dados
13 | rdpInspector.cmd.refresh=Recarregar
14 |
--------------------------------------------------------------------------------
/data/shared/resizer.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | /**
8 | * This object is responsible for setting proper body height
9 | * when the window changes its size.
10 | */
11 | function Resizer(win, app) {
12 | this.win = win;
13 | this.app = app;
14 | this.win.addEventListener("resize", this.onResize.bind(this));
15 |
16 | // Initialize content size
17 | this.onResize();
18 | }
19 |
20 | Resizer.prototype =
21 | /** @lends Resizer */
22 | {
23 | onResize: function() {
24 | var doc = this.win.document;
25 | doc.body.style.height = this.win.innerHeight + "px";
26 | doc.body.style.width = this.win.innerWidth + "px";
27 | }
28 | };
29 |
30 | // Exports from this module
31 | exports.Resizer = Resizer;
32 | });
33 |
--------------------------------------------------------------------------------
/data/inspector/config.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /* globals requirejs */
4 |
5 | // RequireJS configuration
6 | require.config({
7 | baseUrl: ".",
8 | scriptType: "application/javascript;version=1.8",
9 | paths: {
10 | "shared": "../shared",
11 | "jquery": "../lib/jquery/jquery",
12 | "react": "../lib/react/react",
13 | "react-dom": "../lib/react/react-dom",
14 | "bootstrap": "../lib/bootstrap/js/bootstrap",
15 | "immutable": "../lib/immutable/immutable",
16 | "react-bootstrap": "../lib/react-bootstrap/react-bootstrap",
17 | "reps": "../../node_modules/firebug.sdk/lib/reps",
18 | "firebug.sdk": "../../node_modules/firebug.sdk",
19 | "redux": "../lib/redux/redux",
20 | "react-redux": "../lib/redux/react-redux",
21 | }
22 | });
23 |
24 | // Load the main panel module
25 | requirejs(["main"]);
26 |
--------------------------------------------------------------------------------
/chrome/locale/nl/inspector.properties:
--------------------------------------------------------------------------------
1 | rdpInspector.option.showInlineDetails=Pakketdetails inline weergeven
2 | rdpInspector.option.hideInlineDetails=Pakketdetails inline verbergen
3 | rdpInspector.option.cachePackets=Pakketten bufferen voordat de inspecteur wordt geopend
4 | rdpInspector.cmd.clear=Wissen
5 | rdpInspector.cmd.find=Zoeken
6 | rdpInspector.cmd.summary=Samenvatting
7 | rdpInspector.tooltip.sizeSent=Totaal aantal naar de foutopsporingsserver verstuurde gegevens
8 | rdpInspector.tooltip.sizeReceived=Totaal aantal van de foutopsporingsserver ontvangen gegevens
9 | rdpInspector.tooltip.packetsSent=Aantal naar de foutopsporingsserver verstuurde pakketten
10 | rdpInspector.tooltip.packetsReceived=Aantal van de foutopsporingsserver ontvangen pakketten
11 | rdpInspector.label.packets=Pakketten
12 | rdpInspector.label.data=Gegevens
13 | rdpInspector.cmd.refresh=Vernieuwen
14 |
--------------------------------------------------------------------------------
/data/connection-list/config.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /* globals requirejs */
4 |
5 | // RequireJS configuration
6 | require.config({
7 | baseUrl: ".",
8 | scriptType: "application/javascript;version=1.8",
9 | paths: {
10 | "shared": "../shared",
11 | "jquery": "../lib/jquery/jquery",
12 | "react": "../lib/react/react",
13 | "react-dom": "../lib/react/react-dom",
14 | "bootstrap": "../lib/bootstrap/js/bootstrap",
15 | "immutable": "../lib/immutable/immutable",
16 | "react-bootstrap": "../lib/react-bootstrap/react-bootstrap",
17 | "reps": "../../node_modules/firebug.sdk/lib/reps",
18 | "firebug.sdk": "../../node_modules/firebug.sdk",
19 | "redux": "../lib/redux/redux",
20 | "react-redux": "../lib/redux/react-redux",
21 | }
22 | });
23 |
24 | // Load the main panel module
25 | requirejs(["index"]);
26 |
--------------------------------------------------------------------------------
/data/connection-list/containers/main-panel.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // React & Redux
8 | const React = require("react");
9 | const { connect } = require("react-redux");
10 |
11 | // Connections List components
12 | const { ConnectionList } = require("../components/connection-list");
13 |
14 | const MainPanel = React.createClass({
15 | displayName: "MainPanel",
16 |
17 | render() {
18 | return React.createElement(ConnectionList, {
19 | connections: this.props.connections,
20 | onConnectionClick: this.props.onConnectionClick
21 | });
22 | }
23 | });
24 |
25 | function mapStoreToProps(state) {
26 | let { connections } = state;
27 | return { connections };
28 | }
29 |
30 | exports.MainPanel = connect(mapStoreToProps)(MainPanel);
31 |
32 | });
33 |
--------------------------------------------------------------------------------
/data/inspector/containers/app.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // React & Redux
8 | const React = require("react");
9 | const { connect } = require("react-redux");
10 |
11 | // Connections List components
12 | const MainTabbedArea = require("../components/main-tabbed-area");
13 |
14 | const App = React.createClass({
15 | displayName: "App",
16 |
17 | render() {
18 | return React.createElement(MainTabbedArea, {
19 | view: this.props.view,
20 | global: this.props.global,
21 | actors: this.props.actors,
22 | packets: this.props.packets,
23 | });
24 | }
25 | });
26 |
27 | function mapStoreToProps(state) {
28 | let { global, actors, packets } = state;
29 | return { global, actors, packets };
30 | }
31 |
32 | exports.App = connect(mapStoreToProps)(App);
33 |
34 | });
35 |
--------------------------------------------------------------------------------
/data/.eslintrc:
--------------------------------------------------------------------------------
1 | // extends common eslintrc config with "javascript running in a content context" specific configs
2 | {
3 | "extends": "../.eslintrc",
4 | "plugins": [
5 | // prevents tab whitespace when 'indent' rule is disabled
6 | "no-tabs",
7 | "react"
8 | ],
9 | "env": {
10 | // enable browser & amd conventions
11 | "browser": true,
12 | "amd": true
13 | },
14 | "rules": {
15 | // disabled due to conflicts with special indentation in requirejs modules
16 | "indent": 0,
17 | // prevents any usage of tab whitespaces
18 | "no-tabs/at-all": [2],
19 |
20 | // force definition of displayName on React components
21 | "react/display-name": 2,
22 |
23 | // TODO: force propTypes on React Components
24 | "react/prop-types": 0,
25 |
26 | // disabled due to conflicts with capitalized React components names
27 | "new-cap": [0],
28 | },
29 | "globals": {}
30 | }
31 |
--------------------------------------------------------------------------------
/data/connection-list/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/karma-tests/lib/firebug-sdk-shims.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | (function (window, document) {
4 |
5 | "use strict";
6 |
7 | // set the theme-firebug class on the body element
8 | document.body.setAttribute("class", "theme-firebug");
9 |
10 | // bootstrap, firebug.sdk and rdp-inspector stylesheets
11 | var stylesheets = [
12 | "../lib/bootstrap/css/bootstrap.css",
13 | "css/base.css",
14 | "css/toolbox.css",
15 | "css/toolbar.css",
16 | "css/packets-panel.css",
17 | "css/actors-panel.css",
18 | "css/search-box.css",
19 | "css/tree-editor-view.css",
20 | "../../node_modules/firebug.sdk/skin/classic/shared/domTree.css",
21 | "../../node_modules/firebug.sdk/skin/classic/shared/splitter.css"
22 | ];
23 |
24 | stylesheets.forEach(function(url) {
25 | var linkEl = document.createElement("link");
26 | linkEl.setAttribute("href", "/base/data/inspector/" + url);
27 | linkEl.setAttribute("rel", "stylesheet");
28 | document.head.appendChild(linkEl);
29 | })
30 |
31 | })(window, document);
32 |
--------------------------------------------------------------------------------
/data/inspector/components/text-with-tooltip.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | const React = require("react");
9 |
10 | // Constants
11 | const { Tooltip, OverlayTrigger } = require("shared/react-bootstrap-factories");
12 |
13 | const { div } = React.DOM;
14 |
15 | /**
16 | * @template Helper template responsible for rendering a tooltip.
17 | */
18 | const TextWithTooltip = React.createFactory(React.createClass({
19 | displayName: "TextWithTooltip",
20 |
21 | render: function() {
22 | var tooltip = Tooltip({}, this.props.tooltip);
23 | return (
24 | OverlayTrigger({placement: "top", overlay: tooltip, delayShow: 200,
25 | delayHide: 150},
26 | div({className: this.props.className, onClick: this.props.onClick},
27 | this.props.children
28 | )
29 | )
30 | );
31 | }
32 | }));
33 |
34 | // Exports from this module
35 | exports.TextWithTooltip = TextWithTooltip;
36 | });
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | RDP Inspector
2 | =============
3 | Remote debugger protocol inspector
4 |
5 | Instructions
6 | ------------
7 | You should see a new RDP Inspector button at the top-right corner of your
8 | browser window after installation. Click the icon to open RDP Inspector
9 | console and operate developer tools Toolbox to generate some traffic
10 | over RDP. Sent and received packets are visible in the console window.
11 |
12 | * [Learn more](https://github.com/firebug/rdp-inspector/wiki)
13 | * [Download](https://github.com/firebug/rdp-inspector/releases)
14 |
15 | Further Resources
16 | -----------------
17 | * Remote Debugging Protocol: https://wiki.mozilla.org/Remote_Debugging_Protocol
18 | * Add-on SDK: https://developer.mozilla.org/en-US/Add-ons/SDK
19 | * DevTools API: https://developer.mozilla.org/en-US/docs/Tools/DevToolsAPI
20 | * Coding Style: https://github.com/mozilla/addon-sdk/wiki/Coding-style-guide
21 | * DevTools Extension Examples: https://github.com/firebug/devtools-extension-examples
22 | * DevTools/Hacking: https://wiki.mozilla.org/DevTools/Hacking
23 |
--------------------------------------------------------------------------------
/data/inspector/css/toolbar.css:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /******************************************************************************/
4 | /* Toolbar */
5 |
6 | .toolbar {
7 | height: 30px;
8 | padding: 4px;
9 | border-bottom: 1px solid rgb(170, 188, 207);
10 | background-color: rgb(219, 234, 249) !important;
11 | background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
12 | }
13 |
14 | .toolbar .btn {
15 | border-radius: 2px;
16 | color: #141414;
17 | }
18 |
19 | .toolbar select {
20 | margin-left: 3px;
21 | line-height: 1.0;
22 | font-size: 12px;
23 | }
24 |
25 | .toolbar input[type="checkbox"] {
26 | margin-right: 8px;
27 | }
28 |
29 | /******************************************************************************/
30 | /* Tooltip */
31 |
32 | .tooltip .tooltip-inner {
33 | background-color: #EEE1B3;
34 | color: black;
35 | max-width: 300px;
36 | }
37 | .tooltip.bottom .tooltip-arrow {
38 | border-bottom-color: #EEE1B3;
39 | color: black;
40 | }
41 |
--------------------------------------------------------------------------------
/data/inspector/components/packets-message.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | const React = require("react");
9 |
10 | // Constants
11 | const { div } = React.DOM;
12 |
13 | /**
14 | * @template This template renders a generic message within the
15 | * packet list.
16 | */
17 | var PacketsMessage = React.createClass({
18 | /** @lends PacketsMessage */
19 |
20 | displayName: "PacketsMessage",
21 |
22 | render: function() {
23 | var packet = this.props.data;
24 | var message = packet.message;
25 | var time = packet.time;
26 |
27 | var timeText = time.toLocaleTimeString() + "." + time.getMilliseconds();
28 |
29 | // Render summary info
30 | return (
31 | div({className: "packetsMessage"},
32 | div({className: "text"}, message),
33 | div({className: "time"}, timeText)
34 | )
35 | );
36 | }
37 | });
38 |
39 | // Exports from this module
40 | exports.PacketsMessage = React.createFactory(PacketsMessage);
41 | });
42 |
--------------------------------------------------------------------------------
/data/inspector/components/packet-details.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Dependencies
8 | const React = require("react");
9 |
10 | // Firebug SDK
11 | const { TreeView } = require("reps/tree-view");
12 |
13 | // Shortcuts
14 | const { div } = React.DOM;
15 |
16 | /**
17 | * @template This template represents a list of packets displayed
18 | * inside the panel content.
19 | */
20 | var PacketDetails = React.createClass({
21 | /** @lends PacketDetails */
22 |
23 | displayName: "PacketDetails",
24 |
25 | getInitialState: function() {
26 | return {
27 | selectedPacket: null
28 | };
29 | },
30 |
31 | render: function() {
32 | var selectedPacket = this.props.selectedPacket || {};
33 |
34 | return (
35 | div({className: "details"},
36 | TreeView({key: "packet-detail", data: selectedPacket.packet})
37 | )
38 | );
39 | }
40 | });
41 |
42 | // Exports from this module
43 | exports.PacketDetails = React.createFactory(PacketDetails);
44 | });
45 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: node_js
3 | node_js:
4 | - "0.10"
5 | env:
6 | ## Firefox Developer Edition
7 | - FIREFOX_VERSION=aurora-latest
8 | - FIREFOX_VERSION=fx-team
9 |
10 | before_install:
11 | - "export DISPLAY=:99.0"
12 | - "sh -e /etc/init.d/xvfb start"
13 | - "/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16 -extension RANDR"
14 | - npm install -g npm
15 | - npm --version
16 |
17 | before_script:
18 | - npm install jpm -g
19 | - '( [[ "$FIREFOX_VERSION" = "fx-team" ]] && npm install mozilla-download -g && mozilla-download --branch fx-team --product firefox $TRAVIS_BUILD_DIR/../ ) || echo "Building on release $FIREFOX_VERSION"'
20 | - '( [[ "$FIREFOX_VERSION" != "fx-team" ]] && wget "https://download.mozilla.org/?product=firefox-$FIREFOX_VERSION-ssl&os=linux64&lang=en-US" -O $TRAVIS_BUILD_DIR/../firefox.tar.bz2 && cd $TRAVIS_BUILD_DIR/../ && tar xvf firefox.tar.bz2 ) || echo "Building on release $FIREFOX_VERSION"'
21 | - cd $TRAVIS_BUILD_DIR
22 |
23 | script:
24 | - export JPM_FIREFOX_BINARY=$TRAVIS_BUILD_DIR/../firefox/firefox
25 | - export FIREFOX_BIN=$JPM_FIREFOX_BINARY
26 | - npm run travis-ci
27 | - npm run jpm-tests
28 |
--------------------------------------------------------------------------------
/data/inspector/components/packets-limit.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | const React = require("react");
9 |
10 | // Constants
11 | const { div, span } = React.DOM;
12 |
13 | // RDP Window injected APIs
14 | const { Locale } = require("shared/rdp-inspector-window");
15 |
16 | /**
17 | * @template This template is responsible for rendering a message
18 | * at the top of the packet list that informs the user about reaching
19 | * the maximum limit of displayed packets. The message also displays
20 | * number of packets removed from the list.
21 | */
22 | var PacketsLimit = React.createClass({
23 | /** @lends PacketsLimit */
24 |
25 | displayName: "PacketsLimit",
26 |
27 | render: function() {
28 | var removedPackets = this.props.removedPackets;
29 | var label = Locale.$STR("rdpInspector.label.outOfLimit");
30 |
31 | // Render summary info
32 | return (
33 | div({className: "packetsLimit"},
34 | span({className: "text"}, removedPackets + " " + label)
35 | )
36 | );
37 | }
38 | });
39 |
40 | // Exports from this module
41 | exports.PacketsLimit = React.createFactory(PacketsLimit);
42 | });
43 |
--------------------------------------------------------------------------------
/data/inspector/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | "use strict";
4 |
5 | /**
6 | * This file is specified as the 'main' module in package.json
7 | * MDN: https://developer.mozilla.org/en-US/Add-ons/SDK/Tools/package_json
8 | */
9 | let FBTrace = require("firebug.sdk/lib/core/trace.js").FBTrace;
10 | let { main, Loader, override } = require("toolkit/loader");
11 |
12 | // Get default loader options and create one new 'FBTrace' global,
13 | // so it's automatically available in every loaded module.
14 | // Note that FBTrace global should be used for debugging purposes only.
15 | let options = require("@loader/options");
16 |
17 | let defaultGlobals = override(require("sdk/system/globals"), {
18 | FBTrace: FBTrace
19 | });
20 |
21 | options = override(options, {
22 | globals: defaultGlobals,
23 |
24 | // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1123268
25 | modules: override(options.modules || {}, {
26 | "sdk/addon/window": require("sdk/addon/window")
27 | })
28 | });
29 |
30 | // Create custom loader with modified options.
31 | let loader = Loader(options);
32 | let program = main(loader, "./lib/main.js");
33 |
34 | // Exports from this module
35 | exports.main = program.main;
36 | exports.onUnload = program.onUnload;
37 |
--------------------------------------------------------------------------------
/data/lib/react/react-dom.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ReactDOM v0.14.2
3 | *
4 | * Copyright 2013-2015, Facebook, Inc.
5 | * All rights reserved.
6 | *
7 | * This source code is licensed under the BSD-style license found in the
8 | * LICENSE file in the root directory of this source tree. An additional grant
9 | * of patent rights can be found in the PATENTS file in the same directory.
10 | *
11 | */
12 | // Based off https://github.com/ForbesLindesay/umd/blob/master/template.js
13 | ;(function(f) {
14 | // CommonJS
15 | if (typeof exports === "object" && typeof module !== "undefined") {
16 | module.exports = f(require('react'));
17 |
18 | // RequireJS
19 | } else if (typeof define === "function" && define.amd) {
20 | define(['react'], f);
21 |
22 | //
48 |
49 |
50 |
--------------------------------------------------------------------------------
/chrome/content/inspector-window.xul:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
46 |
47 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/data/inspector/actions/packets.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | const types = {
8 | IMPORT_PACKETS_CACHE: "IMPORT_PACKETS_CACHE",
9 | IMPORT_PACKETS_FROMFILE: "IMPORTS_PACKETS_FROMFILE",
10 | INIT_PACKETLIST_OPTIONS: "INIT_PACKETLIST_OPTIONS",
11 | APPEND_PACKET: "APPEND_PACKET",
12 | APPEND_SUMMARY: "APPEND_SUMMARY",
13 | APPEND_MESSAGE: "APPEND_MESSAGE",
14 | EDIT_PACKET: "EDIT_PACKET",
15 | SELECT_PACKET: "SELECT_PACKET",
16 | CLEAR_PACKET_LIST: "CLEAR_PACKET_LIST",
17 | SET_PACKET_FILTER: "SET_PACKET_FILTER",
18 | TOGGLE_PACKETLIST_OPTION: "TOGGLE_PACKETLIST_OPTION",
19 | TOGGLE_PACKETLIST_PAUSE: "TOGGLE_PACKETLIST_PAUSE",
20 | SET_PACKETLIST_ERROR: "SET_PACKETLIST_ERROR",
21 | };
22 |
23 | // export actions types and action creators
24 | module.exports = {
25 | types,
26 |
27 | importPacketsCache(cache) {
28 | return { type: types.IMPORT_PACKETS_CACHE, cache };
29 | },
30 |
31 | importPacketsFromFile(data) {
32 | return { type: types.IMPORT_PACKETS_FROMFILE, data };
33 | },
34 |
35 | initPacketListOptions(options) {
36 | return { type: types.INIT_PACKETLIST_OPTIONS, options };
37 | },
38 |
39 | appendPacket(packetType, packetData) {
40 | return { type: types.APPEND_PACKET, packetType, packetData };
41 | },
42 |
43 | appendSummary() {
44 | let time = new Date();
45 | return { type: types.APPEND_SUMMARY, time };
46 | },
47 |
48 | appendMessage(message) {
49 | let time = new Date();
50 | return { type: types.APPEND_MESSAGE, message, time };
51 | },
52 |
53 | editPacket(packet) {
54 | return { type: types.EDIT_PACKET, packet };
55 | },
56 |
57 | selectPacket(packet) {
58 | return { type: types.SELECT_PACKET, packet };
59 | },
60 |
61 | clearPacketList() {
62 | return { type: types.CLEAR_PACKET_LIST };
63 | },
64 |
65 | togglePacketListOption(name) {
66 | return { type: types.TOGGLE_PACKETLIST_OPTION, name };
67 | },
68 |
69 | togglePacketListPause() {
70 | return { type: types.TOGGLE_PACKETLIST_PAUSE };
71 | },
72 |
73 | setPacketListError(error) {
74 | return { type: types.SET_PACKETLIST_ERROR, error };
75 | }
76 |
77 | };
78 |
79 | });
80 |
--------------------------------------------------------------------------------
/test/test-inspector-service.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | const { InspectorService } = require("../lib/inspector-service");
4 |
5 | const { getMostRecentBrowserWindow } = require("sdk/window/utils");
6 |
7 | // DevTools
8 | const { devtools, gDevTools } = require("firebug.sdk/lib/core/devtools.js");
9 |
10 | function showToolbox(toolId) {
11 | let browser = getMostRecentBrowserWindow();
12 | let tab = browser.gBrowser.mCurrentTab;
13 | let target = devtools.TargetFactory.forTab(tab);
14 | return gDevTools.showToolbox(target, toolId);
15 | }
16 |
17 | function formatException(e) {
18 | return `\n\t${e.fileName}:${e.lineNumber}\n\t${e}`;
19 | }
20 |
21 | exports["test InspectorService"] = function(assert, done) {
22 | showToolbox("webconsole").then((toolbox) => {
23 | assert.ok(toolbox, "toolbox should be defined");
24 |
25 | InspectorService.getInspectorClients(toolbox).then((inspectorClients) => {
26 | assert.ok(inspectorClients, "inspectorClients should be defined");
27 | assert.deepEqual(Object.keys(inspectorClients), ["global", "tab"],
28 | "global and tab keys should be defined");
29 | let { global, tab } = inspectorClients;
30 | assert.equal(typeof global.getActors, "function", "global.getActors function is defined");
31 | assert.equal(typeof tab.getActors, "function", "tab.getActors function is defined");
32 |
33 | Promise.all([global.getActors(), tab.getActors()]).then(([tabActors, globalActors]) => {
34 | const EXPECTED_ACTOR_KEYS = ["actorPool", "extraPools", "factories", "from"];
35 |
36 | assert.deepEqual(Object.keys(globalActors), EXPECTED_ACTOR_KEYS, "globalActors should have the expected attributes");
37 | assert.deepEqual(Object.keys(tabActors), EXPECTED_ACTOR_KEYS, "tabActors should have the expected attributes");
38 |
39 | done();
40 | }).catch((e) => {
41 | assert.fail(`Exception catched during getActors: ${formatException(e)}`);
42 | done();
43 | });
44 | }).catch((e) => {
45 | assert.fail(`Exception catched during getInspectorClients: ${formatException(e)}`);
46 | done();
47 | });
48 | }).catch((e) => {
49 | assert.fail(`Exception catched during showToolbox: ${formatException(e)}`);
50 | done();
51 | });
52 | };
53 |
54 | require("sdk/test").run(exports);
55 |
--------------------------------------------------------------------------------
/data/inspector/components/packets-panel.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Dependencies
8 | const React = require("react");
9 |
10 | // Firebug SDK
11 | const { createFactories } = require("reps/rep-utils");
12 | const { Splitter } = createFactories(require("reps/splitter"));
13 |
14 | // RDP Inspector
15 | const { PacketList } = require("./packet-list");
16 | const { PacketsSidebar } = require("./packets-sidebar");
17 | const { PacketsToolbar } = require("./packets-toolbar");
18 |
19 | // Shortcuts
20 | const { div } = React.DOM;
21 |
22 | /**
23 | * @template This template renders 'Packets' tab body.
24 | */
25 | var PacketsPanel = React.createClass({
26 | /** @lends PacketPanel */
27 |
28 | displayName: "PacketsPanel",
29 |
30 | getInitialState: function() {
31 | return {
32 | packets: this.props.packets,
33 | selectedPacket: null
34 | };
35 | },
36 |
37 | render: function() {
38 | var leftPanel = div({className: "mainPanel"},
39 | PacketsToolbar({
40 | actions: this.props.actions,
41 | showInlineDetails: this.props.showInlineDetails,
42 | packetCacheEnabled: this.props.packetCacheEnabled,
43 | paused: this.props.paused
44 | }),
45 | PacketList({
46 | data: this.props.packets,
47 | actions: this.props.actions,
48 | selectedPacket: this.props.selectedPacket,
49 | searchFilter: this.props.searchFilter,
50 | showInlineDetails: this.props.showInlineDetails,
51 | removedPackets: this.props.removedPackets
52 | })
53 | );
54 |
55 | var rightPanel = div({className: "sidePanel"},
56 | PacketsSidebar({
57 | selectedPacket: this.props.selectedPacket,
58 | editedPacket: this.props.editedPacket,
59 | actions: this.props.actions,
60 | actorIDs: this.props.actorIDs
61 | })
62 | );
63 |
64 | return (
65 | div({className: "packetsPanelBox"},
66 | Splitter({
67 | mode: "vertical",
68 | min: 200,
69 | leftPanel: leftPanel,
70 | rightPanel: rightPanel,
71 | innerBox: div({className: "innerBox"})
72 | })
73 | )
74 | );
75 | }
76 | });
77 |
78 | // Exports from this module
79 | exports.PacketsPanel = React.createFactory(PacketsPanel);
80 | exports.PacketsPanelComponent = PacketsPanel;
81 |
82 | });
83 |
--------------------------------------------------------------------------------
/data/inspector/components/packets-sidebar.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | const React = require("react");
9 |
10 | // RDP Inspector
11 | const { PacketDetails } = require("./packet-details");
12 | const { PacketEditor } = require("./packet-editor");
13 | const { PacketStackSidePanel } = require("./packet-stack-sidepanel");
14 |
15 | // Constants
16 | const { Tabs, Tab } = require("shared/react-bootstrap-factories");
17 |
18 | /**
19 | * @template This template represents a list of packets displayed
20 | * inside the panel content.
21 | */
22 | var PacketsSidebar = React.createClass({
23 | /** @lends PacketsSidebar */
24 |
25 | displayName: "PacketsSidebar",
26 |
27 | getInitialState: function() {
28 | return {
29 | activeKey: 1
30 | };
31 | },
32 |
33 | onTabSelected: function(key) {
34 | this.setState({
35 | activeKey: key
36 | });
37 | },
38 |
39 | componentDidMount: function() {
40 | window.addEventListener("rdpinspector:switchToPacketEditorTab",
41 | this.onSwitchToPacketEditorTab);
42 | },
43 |
44 | componentWillUnmount: function() {
45 | window.removeEventListener("rdpinspector:switchToPacketEditorTab", this.onSwitchToPacketEditorTab);
46 | },
47 |
48 | onSwitchToPacketEditorTab: function() {
49 | this.setState({ activeKey: 2 });
50 | },
51 |
52 | render: function() {
53 | // TODO xxxRpl: externalize and localize sidebar tab titles
54 | return (
55 | Tabs({
56 | className: "sideBarTabbedArea", animation: false,
57 | activeKey: this.state.activeKey,
58 | onSelect: this.onTabSelected
59 | },
60 | Tab({ eventKey: 1, title: "Packet Details" },
61 | PacketDetails({
62 | selectedPacket: this.props.selectedPacket
63 | })
64 | ),
65 | Tab({ eventKey: 2, title: "Send Packet" },
66 | PacketEditor({
67 | actions: this.props.actions,
68 | actorIDs: this.props.actorIDs,
69 | editedPacket: this.props.editedPacket
70 | })
71 | ),
72 | Tab({ eventKey: 3, title: "Stack" },
73 | PacketStackSidePanel({
74 | actions: this.props.actions,
75 | selectedPacket: this.props.selectedPacket
76 | })
77 | )
78 | )
79 | );
80 | }
81 | });
82 |
83 | // Exports from this module
84 | exports.PacketsSidebar = React.createFactory(PacketsSidebar);
85 | exports.PacketsSidebarComponent = PacketsSidebar;
86 | });
87 |
--------------------------------------------------------------------------------
/data/inspector/components/packets-summary.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | const React = require("react");
9 |
10 | // RDP Inspector
11 | const { TextWithTooltip } = require("./text-with-tooltip");
12 |
13 | // RDP Window injected APIs
14 | const { Locale, Str } = require("shared/rdp-inspector-window");
15 |
16 |
17 | // Constants
18 | const { div } = React.DOM;
19 |
20 | /**
21 | * @template This template is responsible for rendering packet summary
22 | * information. The summary can be inserted into the list by clicking
23 | * on 'Summary' button. It displays number of sent and received packets
24 | * and total amount of sent and received data.
25 | */
26 | var PacketsSummary = React.createClass({
27 | /** @lends PacketsSummary */
28 |
29 | displayName: "PacketsSummary",
30 |
31 | render: function() {
32 | var summary = this.props.data;
33 | var time = summary.time;
34 |
35 | var timeText = time.toLocaleTimeString() + "." + time.getMilliseconds();
36 | var sizeReceived = Str.formatSize(summary.data.received);
37 | var sizeSent = Str.formatSize(summary.data.sent);
38 |
39 | // Tooltips
40 | var sizeSentTip = Locale.$STR("rdpInspector.tooltip.sizeSent");
41 | var sizeReceivedTip = Locale.$STR("rdpInspector.tooltip.sizeReceived");
42 | var packetsSentTip = Locale.$STR("rdpInspector.tooltip.packetsSent");
43 | var packetsReceivedTip = Locale.$STR("rdpInspector.tooltip.packetsReceived");
44 |
45 | // Labels
46 | var packetsText = Locale.$STR("rdpInspector.label.packets");
47 | var dataText = Locale.$STR("rdpInspector.label.data");
48 |
49 | // Render summary info
50 | return (
51 | div({className: "packetsSummary"},
52 | div({className: "text"}, packetsText + ": "),
53 | TextWithTooltip({tooltip: packetsSentTip}, summary.packets.sent),
54 | div({className: "slash"}, " / "),
55 | TextWithTooltip({tooltip: packetsReceivedTip}, summary.packets.received),
56 | div({className: "separator"}),
57 | div({className: "text"}, dataText + ": "),
58 | TextWithTooltip({tooltip: sizeSentTip}, sizeSent),
59 | div({className: "slash"}, " / "),
60 | TextWithTooltip({tooltip: sizeReceivedTip}, sizeReceived),
61 | div({className: "separator"}),
62 | div({className: "time"}, timeText)
63 | )
64 | );
65 | }
66 | });
67 |
68 | // Exports from this module
69 | exports.PacketsSummary = React.createFactory(PacketsSummary);
70 | exports.PacketsSummaryComponent = PacketsSummary;
71 | });
72 |
--------------------------------------------------------------------------------
/data/inspector/res/arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
78 |
--------------------------------------------------------------------------------
/lib/webide-connections-monitor.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | "use strict";
4 |
5 | module.metadata = {
6 | "stability": "extermental"
7 | };
8 |
9 | // Firebug SDK
10 | const { Dispatcher } = require("firebug.sdk/lib/dispatcher");
11 | const { Trace/*, TraceError*/ } = require("firebug.sdk/lib/core/trace.js").get(module.id);
12 |
13 | // DevTools
14 | // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=912121
15 | const { devtools, safeRequire } = require("firebug.sdk/lib/core/devtools");
16 | const {
17 | ConnectionManager, Connection
18 | } = safeRequire(devtools, "devtools/client/connection-manager", "devtools/shared/client/connection-manager");
19 | const {
20 | AppManager
21 | } = safeRequire(devtools, "devtools/webide/app-manager", "devtools/client/webide/modules/app-manager");
22 |
23 | /**
24 | * @service This service monitors the connections created by WebIDE and dispatch the
25 | * webide connection lifecycle events, which are used by the InspectorService to keep
26 | * track of the existent debugger clients (and their related toolboxes).
27 | */
28 | const WebIDEConnectionsMonitor =
29 | /** @lends WebIDEConnectionsMonitor */
30 | {
31 | // Initialization
32 |
33 | initialize: function() {
34 | Trace.sysout("WebIDEConnectionsMonitor.initialize;", arguments);
35 |
36 | this.onNewConnection = this.onNewConnection.bind(this);
37 | this.onDestroyConnection = this.onDestroyConnection.bind(this);
38 |
39 | ConnectionManager.on("new", this.onNewConnection);
40 | ConnectionManager.on("destroy", this.onDestroyConnection);
41 | },
42 |
43 | shutdown: function() {
44 | Trace.sysout("WebIDEConnectionsMonitor.shutdown;");
45 |
46 | },
47 |
48 | onNewConnection: function(type, connection) {
49 | Trace.sysout("WebIDEConnectionsMonitor.onNewConnection;", arguments);
50 |
51 | Dispatcher.emit("onWebIDEConnectionCreated", [{ connection, selectedRuntime: AppManager.selectedRuntime }]);
52 |
53 | connection.once(Connection.Events.CONNECTED, () => {
54 | if (AppManager.connection == connection) {
55 |
56 | Dispatcher.emit("onWebIDEConnectionReady", [{ connection, selectedRuntime: AppManager.selectedRuntime }]);
57 | }
58 | });
59 | },
60 |
61 | onDestroyConnection: function(type, connection) {
62 | Trace.sysout("WebIDEConnectionsMonitor.onDestroyConnection;", arguments);
63 |
64 | Dispatcher.emit("onWebIDEConnectionDestroy", [ { connection } ]);
65 | }
66 | };
67 |
68 | // Registration
69 | Dispatcher.register(WebIDEConnectionsMonitor);
70 |
71 | // Exports from this module
72 | exports.WebIDEConnectionsMonitor = WebIDEConnectionsMonitor;
73 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration
2 | // Generated on Sat May 09 2015 14:49:21 GMT+0000 (UTC)
3 |
4 | /* eslint-env node */
5 | /* eslint quotes:0 */
6 |
7 | module.exports = function(config) {
8 |
9 | "use strict";
10 |
11 | var baseKarmaConfig = {
12 |
13 | // base path that will be used to resolve all patterns (eg. files, exclude)
14 | basePath: '',
15 |
16 |
17 | // frameworks to use
18 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
19 | frameworks: ['jasmine', 'requirejs'],
20 |
21 |
22 | // list of files / patterns to load in the browser
23 | files: [
24 | 'karma-tests/lib/firebug-sdk-shims.js',
25 | 'karma-tests/test-main.js',
26 | {pattern: 'node_modules/firebug.sdk/lib/reps/**/*.js', included: false },
27 | {pattern: 'node_modules/firebug.sdk/skin/**/*', included: false},
28 | {pattern: 'data/**/*.js', included: false},
29 | {pattern: 'data/**/*.css', included: false},
30 | {pattern: 'data/**/*.woff', included: false},
31 | {pattern: 'data/**/*.woff2', included: false},
32 | {pattern: 'data/**/*.ttf', included: false},
33 | {pattern: 'data/inspector/res/*', included: false},
34 | {pattern: 'karma-tests/**/*.js', included: false},
35 | {pattern: 'karma-tests/**/*spec.js', included: false}
36 | ],
37 |
38 | // list of files to exclude
39 | exclude: [
40 | ],
41 |
42 | // test results reporter to use
43 | // possible values: 'dots', 'progress'
44 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter
45 | reporters: ['progress'],
46 |
47 | // web server port
48 | port: 9876,
49 |
50 |
51 | // enable / disable colors in the output (reporters and logs)
52 | colors: true,
53 |
54 |
55 | // level of logging
56 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
57 | logLevel: config.LOG_INFO,
58 |
59 | // start these browsers
60 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
61 | browsers: ['Firefox']
62 | };
63 |
64 | config.set(baseKarmaConfig);
65 |
66 | // optionally enable code coverage
67 | if (process.env.CODE_COVERAGE) {
68 | console.log("CODE COVERAGE ENABLED");
69 | config.set({
70 | coverageReporter: {
71 | reporters: [
72 | { type: "html", subdir: "html/" },
73 | { type: "text" },
74 | { type: "text-summary" }
75 | ],
76 | instrumenters: {
77 | istanbul: require("isparta")
78 | }
79 | },
80 | preprocessors: {
81 | 'data/inspector/**/*.js': ['coverage']
82 | },
83 | reporters: baseKarmaConfig.reporters.concat('coverage')
84 | });
85 | }
86 | };
87 |
--------------------------------------------------------------------------------
/karma-tests/components/main-tabbed-area-spec.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 | /* eslint-env jasmine */
3 |
4 | define(function (require) {
5 |
6 | "use strict";
7 |
8 | var ReactDOM = require("react-dom");
9 |
10 | const { ReactLazyFactories } = require("shared/react-helpers");
11 | const { Provider } = ReactLazyFactories(require("react-redux"));
12 | const { App } = ReactLazyFactories(require("inspector/containers/app"));
13 |
14 | var { PacketsSummaryComponent } = require("inspector/components/packets-summary");
15 | var { PacketComponent } = require("inspector/components/packet");
16 | var { PacketsPanelComponent } = require("inspector/components/packets-panel");
17 | var { ActorsPanelComponent } = require("inspector/components/actors-panel");
18 |
19 | var { RDPInspectorView } = require("shared/rdp-inspector-window");
20 |
21 | // actions & store
22 | const store = window.store = require("inspector/store").configureStore();
23 | const actions = require("inspector/actions/index");
24 |
25 | const view = new RDPInspectorView({
26 | window, actions, store,
27 | });
28 |
29 | var testContainerEl = document.querySelector("#test-container");
30 |
31 | view.render = function() {
32 | let provider = Provider({ store }, App({ view }));
33 | this.app = ReactDOM.render(provider, testContainerEl);
34 | };
35 |
36 | view.render();
37 |
38 | describe("MainTabbedArea React Component", function() {
39 | beforeAll(function () {
40 | jasmine.addMatchers(require("karma-tests/custom-react-matchers"));
41 | });
42 |
43 | beforeEach(function () {
44 | view.clear();
45 | });
46 |
47 | afterAll(function () {
48 | ReactDOM.unmountComponentAtNode(document.querySelector("#test-container"));
49 | });
50 |
51 | it("renders without errors", function() {
52 | expect(view).toBeDefined();
53 |
54 | expect(ReactDOM.findDOMNode(view.app)).toEqual(testContainerEl.firstChild);
55 | });
56 |
57 | it("is composed by a PacketsPanel and an ActorsPanel", function () {
58 | var components = [
59 | PacketsPanelComponent,
60 | ActorsPanelComponent
61 | ];
62 |
63 | components.forEach((Component) => {
64 | expect(Component).toBeFoundInReactTree(view.app, 1);
65 | });
66 | });
67 |
68 | it("renders a PacketsSummary on PacketsStore.appendSummary", function () {
69 | view.appendSummary();
70 |
71 | expect(PacketsSummaryComponent).toBeFoundInReactTree(view.app, 1);
72 | });
73 |
74 | it("renders a Packet on PacketsStore.sendPacket", function () {
75 | var packet = JSON.stringify({
76 | to: "root",
77 | type: "requestTypes"
78 | });
79 |
80 | view.onSendPacket({
81 | data: JSON.stringify({
82 | packet: packet,
83 | stack: []
84 | })
85 | });
86 |
87 | expect(PacketComponent).toBeFoundInReactTree(view.app, 1);
88 | });
89 | });
90 | });
91 |
--------------------------------------------------------------------------------
/data/inspector/components/packet-list.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Dependencies
8 | const React = require("react");
9 | const ReactDOM = require("react-dom");
10 |
11 | // RDP Inspector
12 | const { Packet } = require("./packet");
13 | const { PacketsSummary } = require("./packets-summary");
14 | const { PacketsLimit } = require("./packets-limit");
15 | const { PacketsMessage } = require("./packets-message");
16 |
17 | // Shortcuts
18 | const { div } = React.DOM;
19 |
20 | /**
21 | * @template This template represents a list of packets displayed
22 | * inside the panel content.
23 | */
24 | var PacketList = React.createClass({
25 | /** @lends PacketList */
26 |
27 | displayName: "PacketList",
28 |
29 | getInitialState: function() {
30 | return { data: [] };
31 | },
32 |
33 | componentWillUpdate: function() {
34 | var node = ReactDOM.findDOMNode(this);
35 | this.shouldScrollBottom = node.scrollTop +
36 | node.offsetHeight === node.scrollHeight;
37 | },
38 |
39 | componentDidUpdate: function() {
40 | if (this.shouldScrollBottom) {
41 | var node = ReactDOM.findDOMNode(this);
42 | node.scrollTop = node.scrollHeight;
43 | }
44 | },
45 |
46 | render: function() {
47 | var output = [];
48 | var filter = this.props.searchFilter;
49 | var removedPackets = this.props.removedPackets;
50 |
51 | if (removedPackets > 0) {
52 | output.push(PacketsLimit({
53 | removedPackets: removedPackets
54 | }));
55 | }
56 |
57 | var packets = this.props.data;
58 | for (var i in packets) {
59 | var packet = packets[i];
60 |
61 | // Render 'summary' packets.
62 | if (packet.type == "summary") {
63 | output.push(PacketsSummary({
64 | key: packet.id,
65 | data: packet
66 | }));
67 | continue;
68 | }
69 |
70 | // Render 'message' packets.
71 | if (packet.type == "message") {
72 | output.push(PacketsMessage({
73 | key: packet.id,
74 | data: packet
75 | }));
76 | continue;
77 | }
78 |
79 | // Filter out packets which don't match the search token.
80 | if (filter && packet.rawPacket.toLowerCase().indexOf(filter.toLowerCase()) < 0) {
81 | continue;
82 | }
83 |
84 | var selected = this.props.selectedPacket == packet;
85 |
86 | output.push(Packet({
87 | key: packet.id,
88 | data: packet,
89 | actions: this.props.actions,
90 | selected: selected,
91 | showInlineDetails: this.props.showInlineDetails
92 | }));
93 | }
94 |
95 | return (
96 | div({className: "list"},
97 | div({}, output)
98 | )
99 | );
100 | }
101 | });
102 |
103 | // Exports from this module
104 | exports.PacketList = React.createFactory(PacketList);
105 | exports.PacketListComponent = PacketList;
106 | });
107 |
--------------------------------------------------------------------------------
/data/inspector/components/main-tabbed-area.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | var React = require("react");
9 | var ReactDOM = require("react-dom");
10 |
11 | // RDP Inspector
12 | const { ActorsPanel } = require("./actors-panel");
13 | const { PacketsPanel } = require("./packets-panel");
14 | const { SearchBox } = require("./search-box");
15 |
16 | // Constants
17 | const { Tabs, Tab, Alert } = require("shared/react-bootstrap-factories");
18 |
19 | // RDP Window injected APIs
20 | const { Locale } = require("shared/rdp-inspector-window");
21 |
22 | /**
23 | * @template This template is responsible for rendering the main
24 | * application UI. The UI consist from set of tabs (Packets and Actors)
25 | * displaying list of sent/received packets and list of registered
26 | * actors.
27 | */
28 | var MainTabbedArea = React.createClass({
29 | /** @lends MainTabbedArea */
30 |
31 | displayName: "MainTabbedArea",
32 |
33 | getInitialState: function() {
34 | return { packets: [] };
35 | },
36 |
37 | componentDidMount: function() {
38 | var tabbedArea = ReactDOM.findDOMNode(this.refs.tabbedArea);
39 | SearchBox.create(tabbedArea.querySelector(".nav-tabs"));
40 | },
41 |
42 | componentWillUnmount: function() {
43 | var tabbedArea = ReactDOM.findDOMNode(this.refs.tabbedArea);
44 | SearchBox.destroy(tabbedArea.querySelector(".nav-tabs"));
45 | },
46 |
47 | onErrorDismiss: function() {
48 | this.props.view.clearError();
49 | },
50 |
51 | render: function() {
52 | var packets = Locale.$STR("rdpInspector.tab.Packets");
53 | var actors = Locale.$STR("rdpInspector.tab.Actors");
54 | var { error } = this.props.packets;
55 |
56 | return (
57 | Tabs({className: "mainTabbedArea", defaultActiveKey: 1,
58 | animation: false, ref: "tabbedArea"},
59 | error ? Alert({
60 | bsStyle: "warning",
61 | onDismiss: this.onErrorDismiss,
62 | dismissAfter: 2000,
63 | style: {
64 | position: "absolute",
65 | width: "100%",
66 | zIndex: 999999
67 | }
68 | }, error.message) : null,
69 | Tab({ eventKey: 1, title: packets },
70 | PacketsPanel({
71 | packets: this.props.packets.filteredPackets,
72 | actions: this.props.view,
73 | selectedPacket: this.props.packets.selectedPacket,
74 | editedPacket: this.props.packets.editedPacket,
75 | searchFilter: this.props.global.searchFilter,
76 | showInlineDetails: this.props.packets.options.showInlineDetails,
77 | packetCacheEnabled: this.props.packets.options.packetCacheEnabled,
78 | removedPackets: this.props.packets.removedPackets,
79 | paused: this.props.packets.paused,
80 | actorIDs: this.props.actors.actorIDs
81 | })
82 | ),
83 | Tab({ eventKey: 2, title: actors },
84 | ActorsPanel({
85 | actions: this.props.view,
86 | actors: this.props.actors,
87 | searchFilter: this.props.global.searchFilter
88 | })
89 | )
90 | )
91 | );
92 | }
93 | });
94 |
95 | // Exports from this module
96 | module.exports = MainTabbedArea;
97 | });
98 |
--------------------------------------------------------------------------------
/data/inspector/components/factories.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Dependencies
8 | var React = require("react");
9 | var ReactDOM = require("react-dom");
10 |
11 | // Consts
12 | const { tr, td, table, tbody, thead, th, div, h4 } = React.DOM;
13 |
14 | // Templates
15 |
16 | /**
17 | * TODO docs
18 | */
19 | var FactoryRow = React.createFactory(React.createClass({
20 | /** @lends FactoryRow */
21 |
22 | displayName: "FactoryRow",
23 |
24 | render: function() {
25 | var factory = this.props;
26 | return (
27 | tr({className: "poolRow"},
28 | td({}, factory.name),
29 | td({}, factory.prefix),
30 | td({}, factory.ctor)
31 | )
32 | );
33 | }
34 | }));
35 |
36 | /**
37 | * TODO docs
38 | * xxxHonza: localization
39 | */
40 | var FactoryTable = React.createFactory(React.createClass({
41 | /** @lends FactoryTable */
42 |
43 | displayName: "FactoryTable",
44 |
45 | render: function() {
46 | var rows = [];
47 |
48 | var factories = this.props.factories;
49 | for (var i in factories) {
50 | if (this.props.searchFilter &&
51 | JSON.stringify(factories[i]).toLowerCase()
52 | .indexOf(this.props.searchFilter.toLowerCase()) < 0) {
53 | // filter out packets which don't match the filter
54 | continue;
55 | }
56 |
57 | factories[i].key = factories[i].prefix + factories[i].name;
58 | rows.push(FactoryRow(factories[i]));
59 | }
60 |
61 | return (
62 | table({className: "poolTable"},
63 | thead({className: "poolRow"},
64 | th({width: "33%"}, "Name"),
65 | th({width: "33%"}, "Prefix"),
66 | th({width: "33%"}, "Constructor")
67 | ),
68 | tbody(null, rows)
69 | )
70 | );
71 | }
72 | }));
73 |
74 | /**
75 | * TODO docs
76 | */
77 | var FactoryList = React.createFactory(React.createClass({
78 | /** @lends FactoryList */
79 |
80 | displayName: "FactoryList",
81 |
82 | getInitialState: function() {
83 | return {
84 | main: {factories: {}},
85 | child: {factories: {}},
86 | searchFilter: null
87 | };
88 | },
89 | render: function() {
90 | var main = this.state.main;
91 | var child = this.state.child;
92 | var searchFilter = this.state.searchFilter;
93 |
94 | // xxxHonza: localization
95 | return (
96 | div({className: "poolContainer"},
97 | h4(null, "Main Process - Global Factories"),
98 | FactoryTable({ factories: main.factories.global, searchFilter: searchFilter }),
99 | h4(null, "Main Process - Tab Factories"),
100 | FactoryTable({ factories: main.factories.tab, searchFilter: searchFilter }),
101 | h4(null, "Child Process - Global Factories"),
102 | FactoryTable({ factories: child.factories.global, searchFilter: searchFilter }),
103 | h4(null, "Child Process - Tab Factories"),
104 | FactoryTable({ factories: child.factories.tab, searchFilter: searchFilter })
105 | )
106 | );
107 | }
108 | }));
109 |
110 | // TODO: turn this into a more React approach
111 | var Factories = {
112 | render: function(parentNode) {
113 | return ReactDOM.render(FactoryList(), parentNode);
114 | }
115 | };
116 |
117 | // Exports from this module
118 | exports.Factories = Factories;
119 |
120 | });
121 |
--------------------------------------------------------------------------------
/data/inspector/css/toolbox.css:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /******************************************************************************/
4 | /* Main Tabs */
5 |
6 | .mainTabbedArea {
7 | background-color: rgb(219, 234, 249);
8 | background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
9 | }
10 |
11 | .mainTabbedArea li a {
12 | padding: 3px 8px;
13 | font-weight: bold;
14 | color: #565656;
15 | }
16 |
17 | .mainTabbedArea li.active a,
18 | .mainTabbedArea li.active a:focus {
19 | background-color: rgb(247, 251, 254);
20 | border: 1px solid rgb(170, 188, 207);
21 | border-bottom-color: transparent;
22 | }
23 |
24 | .mainTabbedArea li:hover a {
25 | border: 1px solid #C8C8C8;
26 | border-bottom: 1px solid transparent;
27 | background-color: transparent !important;
28 | }
29 |
30 | .mainTabbedArea li.active:hover a {
31 | border: 1px solid rgb(170, 188, 207) !important;
32 | background-color: rgb(247, 251, 254) !important;
33 | border-bottom-color: transparent !important;
34 | }
35 |
36 | .mainTabbedArea .nav-tabs {
37 | padding-top: 3px;
38 | padding-left: 3px;
39 | height: 30px;
40 | border-bottom-color: rgb(170, 188, 207);
41 | background-color: rgb(219, 234, 249) !important;
42 | background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
43 | }
44 |
45 | .tab-content {
46 | /* xxxHonza: minus the height of the tab bar */
47 | height: calc(100% - 31px);
48 | }
49 |
50 | .tab-pane {
51 | height: 100%;
52 | padding: 0px;
53 | background-color: white;
54 | }
55 |
56 | /******************************************************************************/
57 | /* SideBar */
58 |
59 | .sideBarTabbedArea {
60 | height: 30px;
61 | border-bottom: 1px solid rgb(170, 188, 207);
62 | background-color: rgb(219, 234, 249) !important;
63 | background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
64 | }
65 |
66 | .sideBarTabbedArea li a {
67 | padding: 4px 9px;
68 | font-weight: normal;
69 | font-size: 12px;
70 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
71 | color: #141414;
72 | }
73 |
74 | .sideBarTabbedArea li.active a,
75 | .sideBarTabbedArea li.active a:focus {
76 | background-color: white;
77 | border: 1px solid rgb(170, 188, 207);
78 | border-bottom-color: transparent;
79 | color: #141414;
80 | }
81 |
82 | .sideBarTabbedArea li:hover a {
83 | border-color: #C8C8C8;
84 | background-color: transparent;
85 | }
86 |
87 | .sideBarTabbedArea li.active:hover a {
88 | border: 1px solid rgb(170, 188, 207) !important;
89 | border-bottom-color: transparent !important;
90 | color: #141414 !important;
91 | }
92 |
93 | .sideBarTabbedArea.nav-tabs {
94 | padding-top: 3px;
95 | padding-left: 3px;
96 | }
97 |
98 | /******************************************************************************/
99 | /* Panels */
100 |
101 | .mainPanel {
102 | height: 100%;
103 | }
104 |
105 | .sidePanel {
106 | height: 100%;
107 | }
108 |
109 | .sidePanel > DIV {
110 | height: 100%;
111 | }
112 |
113 | /******************************************************************************/
114 | /* Actors Panels */
115 |
116 | .actorsPanelBox {
117 | height: calc(100% - 30px);
118 | }
119 |
120 | .actorsScrollBox {
121 | height: 100%;
122 | padding: 10px;
123 | overflow: auto;
124 | }
125 |
--------------------------------------------------------------------------------
/karma-tests/components/packets-toolbar-spec.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jasmine */
2 |
3 | define(function (require) {
4 |
5 | "use strict";
6 |
7 | var React = require("react");
8 | var ReactDOM = require("react-dom");
9 | var { TestUtils } = React.addons;
10 |
11 | var { PacketsToolbar } = require("inspector/components/packets-toolbar");
12 |
13 | var packetsToolbar = TestUtils.renderIntoDocument(PacketsToolbar({}));
14 |
15 | var ReactMatchers = require("karma-tests/custom-react-matchers");
16 |
17 | describe("PacketsToolbar", () => {
18 | beforeAll(() => {
19 | jasmine.addMatchers(ReactMatchers);
20 | });
21 |
22 | it("renders without errors", () => {
23 | expect(packetsToolbar).toBeDefined();
24 |
25 | expect(ReactDOM.findDOMNode(packetsToolbar)).toBeDefined();
26 | });
27 |
28 | it("contains a 'File' DropdownButton", () => {
29 | expect(packetsToolbar.refs.fileMenu).toBeDefined();
30 | });
31 |
32 | describe("File DropdownButton Menu", () => {
33 | // spy actions that should be called
34 | var actions = {
35 | loadPacketsFromFile: jasmine.createSpy("loadPacketsFromFile"),
36 | savePacketsToFile: jasmine.createSpy("savePacketsToFile")
37 | };
38 |
39 | beforeAll(() => {
40 | packetsToolbar = TestUtils.renderIntoDocument(PacketsToolbar({
41 | actions: actions
42 | }));
43 | });
44 |
45 | it("contains a Load and Save MenuItems", () => {
46 | // load and save menuitems should be defined
47 | expect(packetsToolbar.refs.fileLoad).toBeDefined();
48 | expect(packetsToolbar.refs.fileSave).toBeDefined();
49 | });
50 |
51 | it("calls props.actions.loadPacketsFromFile on Load clicks", () => {
52 | var node = ReactDOM.findDOMNode(packetsToolbar.refs.fileLoad);
53 | TestUtils.Simulate.click(node.querySelector("a"));
54 | expect(actions.loadPacketsFromFile).toHaveBeenCalled();
55 | });
56 |
57 | it("calls props.actions.savePacketsFromFile on Save clicks", () => {
58 | var node = ReactDOM.findDOMNode(packetsToolbar.refs.fileSave);
59 | TestUtils.Simulate.click(node.querySelector("a"));
60 | expect(actions.savePacketsToFile).toHaveBeenCalled();
61 | });
62 | });
63 |
64 | describe("Options DropdownButton Menu", () => {
65 | // spy actions that should be called
66 | var actions = {
67 | onShowInlineDetails: jasmine.createSpy("onShowInlineDetails"),
68 | onPacketCacheEnabled: jasmine.createSpy("onPacketCacheEnabled")
69 | };
70 |
71 | beforeAll(() => {
72 | packetsToolbar = TestUtils.renderIntoDocument(PacketsToolbar({
73 | actions: actions
74 | }));
75 | });
76 |
77 | it("contains a 'Show Inline Details' and 'Packets Cache' MenuItems", () => {
78 | // load and save menuitems should be defined
79 | expect(packetsToolbar.refs.optionShowInlineDetails).toBeDefined();
80 | expect(packetsToolbar.refs.optionCachePackets).toBeDefined();
81 | });
82 |
83 | it("calls props.actions.onShowInlineDetails on 'Show Inline Details' clicks", () => {
84 | var node = ReactDOM.findDOMNode(packetsToolbar.refs.optionShowInlineDetails);
85 | TestUtils.Simulate.click(node.querySelector("a"));
86 | expect(actions.onShowInlineDetails).toHaveBeenCalled();
87 | });
88 |
89 | it("calls props.actions.onPacketCacheEnabled on 'Packet Cache' clicks", () => {
90 | var node = ReactDOM.findDOMNode(packetsToolbar.refs.optionCachePackets);
91 | TestUtils.Simulate.click(node.querySelector("a"));
92 | expect(actions.onPacketCacheEnabled).toHaveBeenCalled();
93 | });
94 | });
95 | });
96 |
97 | });
98 |
--------------------------------------------------------------------------------
/chrome/skin/classic/shared/search.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
87 |
--------------------------------------------------------------------------------
/data/inspector/components/pools.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Dependencies
8 | const React = require("react");
9 | const { tr, td, table, tbody, thead, th, div, h4 } = React.DOM;
10 |
11 | // Templates
12 |
13 | /**
14 | * TODO docs
15 | */
16 | var PoolRow = React.createFactory(React.createClass({
17 | /** @lends PoolRow */
18 |
19 | displayName: "PoolRow",
20 |
21 | render: function() {
22 | var actor = this.props;
23 | return (
24 | tr({className: "poolRow"},
25 | td({}, actor.actorID),
26 | td({}, actor.actorPrefix),
27 | td({}, actor.typeName),
28 | td({}, actor.parentID),
29 | td({}, actor.constructor)
30 | )
31 | );
32 | }
33 | }));
34 |
35 | /**
36 | * TODO docs
37 | * xxxHonza: localization
38 | */
39 | var PoolTable = React.createFactory(React.createClass({
40 | /** @lends PoolTable */
41 |
42 | displayName: "PoolTable",
43 |
44 | render: function() {
45 | var rows = [];
46 |
47 | // Iterate array of actors.
48 | var actors = this.props.pool;
49 | for (var i in actors) {
50 | if (this.props.searchFilter &&
51 | JSON.stringify(actors[i]).toLowerCase()
52 | .indexOf(this.props.searchFilter.toLowerCase()) < 0) {
53 | // filter out packets which don't match the filter
54 | continue;
55 | }
56 | actors[i].key = actors[i].actorID;
57 | rows.push(PoolRow(actors[i]));
58 | }
59 |
60 | // Pools are mixed with Actor objects (created using CreateClass).
61 | var className = "poolTable";
62 | if (this.props.actorClass) {
63 | className += " actorClass";
64 | }
65 |
66 | var id = this.props.id ? "ID: " + this.props.id : "";
67 |
68 | return (
69 | div({},
70 | h4({}, "Pool" + id),
71 | table({className: className},
72 | thead({className: "poolRow"},
73 | th({width: "20%"}, "Actor ID"),
74 | th({width: "20%"}, "Prefix"),
75 | th({width: "20%"}, "TypeName"),
76 | th({width: "20%"}, "Parent"),
77 | th({width: "20%"}, "Constructor")
78 | ),
79 | tbody(null, rows)
80 | )
81 | )
82 | );
83 | }
84 | }));
85 |
86 | /**
87 | * TODO docs
88 | */
89 | var PoolList = React.createFactory(React.createClass({
90 | /** @lends PoolList */
91 |
92 | displayName: "PoolList",
93 |
94 | getInitialState: function() {
95 | return {
96 | pools: []
97 | };
98 | },
99 |
100 | render: function() {
101 | var pools = [];
102 |
103 | for (var i in this.state.pools) {
104 | var poolData = this.state.pools[i];
105 | var pool = poolData.pool;
106 | var poolId = poolData.id;
107 |
108 | var actorClass = false;
109 |
110 | // xxxHonza: there are actors stored as pools.
111 | // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1119790#c1
112 | if (!Array.isArray(pool)) {
113 | pool = [pool];
114 | actorClass = true;
115 | }
116 |
117 | pools.push(PoolTable({
118 | pool: pool,
119 | actorClass: actorClass,
120 | id: poolId,
121 | key: i,
122 | searchFilter: this.state.searchFilter
123 | }));
124 | }
125 |
126 | return (
127 | div({className: "poolContainer"},
128 | pools
129 | )
130 | );
131 | }
132 | }));
133 |
134 | var Pools = {
135 | render: function(parentNode) {
136 | return React.render(PoolList(), parentNode);
137 | }
138 | };
139 |
140 | // Exports from this module
141 | exports.Pools = Pools;
142 |
143 | });
144 |
--------------------------------------------------------------------------------
/chrome/locale/en-US/toolbox.properties:
--------------------------------------------------------------------------------
1 | # LOCALIZATION NOTE (rdpInspector.title): RDP Inspector extension title
2 | rdpInspector.title=RDP Inspector
3 |
4 | # LOCALIZATION NOTE (rdpInspector.button.title, rdpInspector.button.tip):
5 | # Label and a tooltip for RDP Inspector start button available in the
6 | # Firefox toolbar and Style Editor panel. This button opens RDP Inspector
7 | # window.
8 | rdpInspector.startButton.title=RDP Inspector
9 | rdpInspector.startButton.tip=Remote debugging protocol inspector.
10 |
11 | # LOCALIZATION NOTE (rdpInspector.menu.about.label, rdpInspector.menu.about.tip):
12 | # RDP Inspector menu label. The menu is available in RDP Inspector start
13 | # button located in Firefox toolbar.
14 | rdpInspector.menu.about.label=About RDP Inspector...
15 | rdpInspector.menu.about.tip=Information about RDP Inspector
16 |
17 | # LOCALIZATION NOTE (rdpInspector.menu.visitHomePage.label, rdpInspector.menu.visitHomePage.tip):
18 | # RDP Inspector menu label. The menu is available in RDP Inspector start
19 | # button located in Firefox toolbar.
20 | rdpInspector.menu.visitHomePage.label=Visit Home Page...
21 | rdpInspector.menu.visitHomePage.tip=Learn more about RDP Inspector
22 |
23 | # LOCALIZATION NOTE (rdpInspector.menu.reportIssue.label, rdpInspector.menu.reportIssue.tip):
24 | # RDP Inspector menu label. The menu is available in RDP Inspector start
25 | # button located in Firefox toolbar.
26 | rdpInspector.menu.reportIssue.label=Report Issue...
27 | rdpInspector.menu.reportIssue.tip=Did you find a bug or do you need a new feature? Let us know!
28 |
29 | # LOCALIZATION NOTE (rdpInspector.menu.group.label, rdpInspector.menu.group.tip):
30 | # RDP Inspector menu label. The menu is available in RDP Inspector start
31 | # button located in Firefox toolbar.
32 | rdpInspector.menu.group.label=Discussion Group...
33 | rdpInspector.menu.group.tip=Open the discussion group site (shared with Firebug)
34 |
35 | # LOCALIZATION NOTE (rdpInspector.menu.options.label):
36 | # RDP Inspector menu label. The menu is available in RDP Inspector start button locate in Firefox toolbar.
37 | rdpInspector.menu.options.label=Options
38 |
39 | # LOCALIZATION NOTE (rdpInspector.menu.packetCache.label,rdpInspector.menu.packetCache.tip):
40 | # RDP Inspector menu label. The menu is available in RDP Inspector start
41 | # button located in Firefox toolbar, inside the Options sub-menu.
42 | rdpInspector.menu.packetCache.label=Packet Cache
43 | rdpInspector.menu.packetCache.tip=Store packets in a cache before the console is opened.
44 |
45 | # LOCALIZATION NOTE (rdpInspector.menu.showInlineDetails.label,rdpInspector.menu.showInlineDetails.tip):
46 | # RDP Inspector menu label. The menu is available in RDP Inspector start
47 | # button located in Firefox toolbar, inside the Options sub-menu.
48 | rdpInspector.menu.showInlineDetails.label=Show Packet Details Inline
49 | rdpInspector.menu.showInlineDetails.tip=Show a detailed tree view of the Packet content.
50 |
51 | # LOCALIZATION NOTE (rdpInspector.menu.autoOpenOnWebIDEConnection.label,rdpInspector.menu.autoOpenOnWebIDEConnection.tip):
52 | # RDP Inspector menu label. The menu is available in RDP Inspector start
53 | # button located in Firefox toolbar, inside the Options sub-menu.
54 | rdpInspector.menu.autoOpenOnWebIDEConnection.label=Open automatically on new WebIDE connections
55 | rdpInspector.menu.autoOpenOnWebIDEConnection.tip=Open an RDP inspector window automatically on every new WebIDE connections.
56 |
57 | # LOCALIZATION NOTE (rdpInspector.menu.connectionList.label, rdpInspector.menu.connectionList.tip):
58 | # RDP Inspector menu label. The menu is available in RDP Inspector start
59 | # button located in Firefox toolbar.
60 | rdpInspector.menu.connectionList.label=Connect to...
61 | rdpInspector.menu.connectionList.tip=Open a dialog which lists all the RDP Connections available to the RDPInspector
62 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rdpinspector",
3 | "title": "RDP Inspector",
4 | "id": "rdpinspector@getfirebug.com",
5 | "description": "Remote debugger protocol inspector",
6 | "author": "Firebug Working Group",
7 | "icon": "chrome://rdpinspector/skin/icon32.png",
8 | "homepage": "https://github.com/firebug/rdp-inspector/wiki",
9 | "forum": "https://groups.google.com/forum/#!forum/firebug",
10 | "contributors": [
11 | "Jan Odvarko (Mozilla Corp.)",
12 | "Luca Greco",
13 | "Sebastian Zartner",
14 | "Jarda Snajdr"
15 | ],
16 | "translators": [
17 | "YFdyh000 (zh-CN)",
18 | "Markh van BabelZilla.org (nl)",
19 | "Marco Aurelio Krause (pt-BR)"
20 | ],
21 | "license": "BSD-3-Clause",
22 | "version": "1.2.5",
23 | "scripts": {
24 | "test": "npm run karma-tests && npm run jpm-tests",
25 | "karma-tests": "karma start --single-run --reporters spec",
26 | "karma-coverage": "CODE_COVERAGE=true npm run karma-tests -- --reporters spec,coverage",
27 | "watch-karma-tests": "karma start --no-single-run --reporters spec --auto-watch",
28 | "watch-karma-coverage": "CODE_COVERAGE=true npm run watch-karma-tests",
29 | "jpm-tests": "jpm test",
30 | "travis-ci": "npm run karma-coverage && npm run lint",
31 | "lint-content": "eslint data/inspector data/connection-list/ data/shared/ && eslint karma-tests/",
32 | "lint-addon": "eslint lib",
33 | "lint": "npm run lint-content && npm run lint-addon"
34 | },
35 | "engines": {
36 | "firefox": ">=38.0"
37 | },
38 | "main": "index.js",
39 | "repository": {
40 | "type": "git",
41 | "url": "https://github.com/firebug/rdp-inspector.git"
42 | },
43 | "bugs": {
44 | "url": "https://github.com/firebug/rdp-inspector/issues"
45 | },
46 | "preferences-branch": "rdpinspector",
47 | "preferences": [
48 | {
49 | "name": "autoOpenOnWebIDEConnection",
50 | "title": "Open RDP Inspector window automatically on new WebIDE connections",
51 | "description": "auto-open an RDP inspector window on every new WebIDE connections",
52 | "type": "bool",
53 | "value": false
54 | },
55 | {
56 | "name": "showInlineDetails",
57 | "title": "Show Packet Details Inline",
58 | "description": "Show a detailed tree view of the Packet content",
59 | "type": "bool",
60 | "value": false
61 | },
62 | {
63 | "name": "packetLimit",
64 | "title": "Maximum number of displayed packets",
65 | "description": "Maximum number of packets displayed in the RDP Inspector console",
66 | "type": "integer",
67 | "value": 500
68 | },
69 | {
70 | "name": "packetCacheEnabled",
71 | "title": "Enable packets caching",
72 | "type": "bool",
73 | "value": false
74 | },
75 | {
76 | "name": "packetCacheSize",
77 | "title": "Maximum number of packets in the cache",
78 | "description": "Maximum number of packets stored in a cache that's holding packets before the console is opened.",
79 | "type": "integer",
80 | "value": 200
81 | }
82 | ],
83 | "dependencies": {
84 | "firebug.sdk": "~0.6.7"
85 | },
86 | "devDependencies": {
87 | "eslint": "^0.21.0",
88 | "eslint-plugin-no-tabs": "git://github.com/rpl/eslint-plugin-no-tabs",
89 | "eslint-plugin-react": "git://github.com/rpl/eslint-plugin-react#fix/displayName-and-propTypes-on-jsx-false",
90 | "isparta": "^3.0.3",
91 | "jasmine-core": "^2.3.2",
92 | "karma": "^0.12.31",
93 | "karma-cli": "0.0.4",
94 | "karma-coverage": "^0.3.1",
95 | "karma-firefox-launcher": "^0.1.4",
96 | "karma-jasmine": "^0.3.5",
97 | "karma-requirejs": "^0.2.2",
98 | "karma-spec-reporter": "0.0.19",
99 | "requirejs": "^2.1.17"
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/lib/transport-observer.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | "use strict";
4 |
5 | module.metadata = {
6 | "stability": "experimental"
7 | };
8 |
9 | // Add-on SDK
10 | const { Class } = require("sdk/core/heritage");
11 | const { EventTarget } = require("sdk/event/target");
12 |
13 | // Firebug SDK
14 | const { Trace/*, TraceError*/ } = require("firebug.sdk/lib/core/trace.js").get(module.id);
15 | const { Arr } = require("firebug.sdk/lib/core/array.js");
16 | //const { Options } = require("firebug.sdk/lib/core/options.js");
17 |
18 | /**
19 | * This object registers a listener in transport layer that is associated
20 | * with given client object {@DebuggerClient}. All sent and received
21 | * packets are consequently forwarded to other listeners.
22 | * One of the listeners is the {@ToolboxOverlay} object that implements
23 | * packet caching (and also forwards packets to RDP Window if it exists).
24 | */
25 | const TransportObserver = Class(
26 | /** @lends TransportObserver */
27 | {
28 | extends: EventTarget,
29 |
30 | // Initialization
31 |
32 | initialize: function(options) {
33 | Trace.sysout("TransportObserver.initialize;", options);
34 |
35 | this.listeners = [];
36 |
37 | this.client = options.client;
38 |
39 | this.send = this.send.bind(this);
40 | this.onPacket = this.onPacket.bind(this);
41 | this.onBulkPacket = this.onBulkPacket.bind(this);
42 | this.startBulkSend = this.startBulkSend.bind(this);
43 | this.onClosed = this.onClosed.bind(this);
44 |
45 | let transport = this.client._transport;
46 | transport.on("send", this.send);
47 | transport.on("onPacket", this.onPacket);
48 | transport.on("onBulkPacket", this.onBulkPacket);
49 | transport.on("startBulkSend", this.startBulkSend);
50 | transport.on("onClosed", this.onClosed);
51 |
52 | transport.on("packet", this.onPacket);
53 | transport.on("bulkpacket", this.onBulkPacket);
54 | transport.on("startbulksend", this.startBulkSend);
55 | transport.on("close", this.onClosed);
56 | },
57 |
58 | destroy: function() {
59 | Trace.sysout("TransportObserver.destroy;");
60 |
61 | let transport = this.client._transport;
62 | transport.off("send", this.send);
63 | transport.off("onPacket", this.onPacket);
64 | transport.off("onBulkPacket", this.onBulkPacket);
65 | transport.off("startBulkSend", this.startBulkSend);
66 | transport.off("onClosed", this.onClosed);
67 |
68 | transport.off("packet", this.onPacket);
69 | transport.off("bulkpacket", this.onBulkPacket);
70 | transport.off("startbulksend", this.startBulkSend);
71 | transport.off("close", this.onClosed);
72 | },
73 |
74 | // Connection Events
75 |
76 | send: function(eventId, packet) {
77 | Trace.sysout("PACKET SEND " + JSON.stringify(packet), packet);
78 |
79 | packet = JSON.parse(JSON.stringify(packet));
80 |
81 | this.listeners.forEach(listener => {
82 | listener.onSendPacket(packet);
83 | });
84 | },
85 |
86 | onPacket: function(eventId, packet) {
87 | Trace.sysout("PACKET RECEIVED; " + JSON.stringify(packet), packet);
88 |
89 | packet = JSON.parse(JSON.stringify(packet));
90 |
91 | this.listeners.forEach(listener => {
92 | listener.onReceivePacket(packet);
93 | });
94 | },
95 |
96 | startBulkSend: function(/*eventId, header*/) {
97 | },
98 |
99 | onBulkPacket: function(/*eventId, packet*/) {
100 | },
101 |
102 | onClosed: function(/*eventId, status*/) {
103 | },
104 |
105 | // Listeners
106 |
107 | addListener: function(listener) {
108 | this.listeners.push(listener);
109 | },
110 |
111 | removeListener: function(listener) {
112 | Arr.remove(this.listeners, listener);
113 | }
114 | });
115 |
116 | // Exports from this module
117 | exports.TransportObserver = TransportObserver;
118 |
--------------------------------------------------------------------------------
/chrome/locale/en-US/inspector.properties:
--------------------------------------------------------------------------------
1 | # LOCALIZATION NOTE (rdpInspector.tab.Packets, rdpInspector.tab.Actors)
2 | # A label for main application tabs.
3 | rdpInspector.tab.Packets=Packets
4 | rdpInspector.tab.Actors=Actors
5 |
6 | # LOCALIZATION NOTE (rdpInspector.option.showInlineDetails,
7 | # rdpInspector.option.showInlineDetails): Label and
8 | # tooltip for an option that can be set within the Packets tab. If set to true
9 | # every packet display inline preview of packet properties (collapsed
10 | # by default)
11 | rdpInspector.option.showInlineDetails=Show Packet Details Inline
12 | rdpInspector.option.showInlineDetails.tip=Show a detailed tree view of the Packet content.
13 |
14 | # LOCALIZATION NOTE (rdpInspector.option.packetCacheEnabled, rdpInspector.options.packetCacheEnabled.tip): Label and
15 | # tooltip for an option that can be set within the Packets tab. If set to true
16 | # the inspector caches packets that are sent/received before the
17 | # inspector window is opened (to see also packets that happens
18 | # at the very beginning)
19 | rdpInspector.option.packetCacheEnabled=Packet Cache
20 | rdpInspector.option.packetCacheEnabled.tip=Store packets in a cache before the console is opened.
21 |
22 | # LOCALIZATION NOTE (rdpInspector.cmd.clear): Label for a toolbar button
23 | # in the Packets tab. This command clears the packet list.
24 | rdpInspector.cmd.clear=Clear
25 |
26 | # LOCALIZATION NOTE (rdpInspector.cmd.find): Label for a toolbar button
27 | # in the Packets tab. This command opens standard Find bar at the bottom
28 | # of the Inspector window.
29 | rdpInspector.cmd.find=Find
30 |
31 | # LOCALIZATION NOTE (rdpInspector.cmd.summary): Label for a toolbar button
32 | # in the Packets tab. This command inserts a summary separator in the
33 | # packets list.
34 | rdpInspector.cmd.summary=Summary
35 |
36 | # LOCALIZATION NOTE (rdpInspector.tooltip.sizeSent, rdpInspector.tooltip.sizeReceived,
37 | # rdpInspector.tooltip.packetsSent, rdpInspector.tooltip.packetsReceived):
38 | # A tooltip for summary info in the packet list.
39 | rdpInspector.tooltip.sizeSent=Total amount of data sent to the debugger server
40 | rdpInspector.tooltip.sizeReceived=Total amount of data received from the debugger server
41 | rdpInspector.tooltip.packetsSent=Number of packets sent to the debugger server
42 | rdpInspector.tooltip.packetsReceived=Number of packets received from the debugger server
43 |
44 | # LOCALIZATION NOTE (rdpInspector.label.packets, rdpInspector.label.data)
45 | # A label for summary info in the packet list.
46 | rdpInspector.label.packets=Packets
47 | rdpInspector.label.data=Data
48 |
49 | # LOCALIZATION NOTE (rdpInspector.cmd.refresh) A label used on Actor's
50 | # tab toolbar. It's used to refresh the tab's content.
51 | rdpInspector.cmd.refresh=Refresh
52 |
53 | # LOCALIZATION NOTE (rdpInspector.label.sent, rdpInspector.label.to,
54 | # rdpInspector.label.received, rdpInspector.label.from): A label for
55 | # packets displayed in the packet list.
56 | rdpInspector.label.sent=Sent
57 | rdpInspector.label.to=to
58 | rdpInspector.label.received=Received
59 | rdpInspector.label.from=from
60 |
61 | # LOCALIZATION NOTE (rdpInspector.label.outOfLimit) A label displayed
62 | # at the top of the packet list in case the number of displayed packets
63 | # reached maximum limit.
64 | rdpInspector.label.outOfLimit=packets removed
65 |
66 | # LOCALIZATION NOTE (rdpInspector.label.Paused, rdpInspector.label.Unpaused):
67 | # A label used for pause/unpause packet collecting. The label is for a message
68 | # that is printed into the packet list when the user click the Pause button
69 | # in the toolbar.
70 | rdpInspector.label.Paused=Paused
71 | rdpInspector.label.Unpaused=Unpaused
72 |
73 | # LOCALIZATION NOTE (rdpInspector.label.MainProcess, rdpInspector.label.ChildProcess,
74 | # rdpInspector.ActorsFactories):
75 | # Labels used for the actors sub-panel selector in the actors panel toolbar.
76 | rdpInspector.label.MainProcess=Main Process
77 | rdpInspector.label.ChildProcess=Child Process
78 | rdpInspector.label.ActorsFactories=Actors Factories
79 |
80 | # LOCALIZATION NOTE (rdpInspector.menu.File, rdpInspector.menu.Options,
81 | # rdpInspector.cmd.load, rdpInspector.cmd.save):
82 | # Labels for the dropdown menus in the packets panel toolbar.
83 | rdpInspector.menu.File=File
84 | rdpInspector.menu.Options=Options
85 | rdpInspector.cmd.load=Load
86 | rdpInspector.cmd.save=Save
87 |
--------------------------------------------------------------------------------
/karma-tests/components/packet-spec.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 | /* eslint-env jasmine */
3 |
4 | define(function (require) {
5 |
6 | "use strict";
7 |
8 | var React = require("react");
9 | var ReactDOM = require("react-dom");
10 | var { TestUtils } = React.addons;
11 |
12 | var { Packet } = require("inspector/components/packet");
13 | const { TreeViewComponent } = require("reps/tree-view");
14 |
15 | var ReactMatchers = require("karma-tests/custom-react-matchers");
16 |
17 | describe("Packet", () => {
18 | beforeAll(() => {
19 | jasmine.addMatchers(ReactMatchers);
20 | });
21 |
22 | //TODO: currently skipped, until TreeView component is exported from firebug.sdk
23 | xit("contains a TreeView for props.data.packet only if props.showInlineDetails is true", () => {
24 | var packet;
25 |
26 | var data = {
27 | type: "receive",
28 | size: 0,
29 | id: 1,
30 | time: new Date("2015-06-09T16:48:50.162Z"),
31 | packet: {}
32 | };
33 |
34 | packet = TestUtils.renderIntoDocument(Packet({
35 | showInlineDetails: false,
36 | data: data
37 | }));
38 |
39 | //TODO: needs TreeView component exported from firebug.sdk
40 | expect(TreeViewComponent).toBeFoundInReactTree(packet, 0);
41 |
42 | packet = TestUtils.renderIntoDocument(Packet({
43 | showInlineDetails: true,
44 | data: data
45 | }));
46 |
47 | //TODO: needs TreeView component exported from firebug.sdk
48 | expect(TreeViewComponent).toBeFoundInReactTree(packet, 1);
49 | });
50 |
51 | describe("context menu actions", () => {
52 | it("has 'Edit and Resent' action in the sent packet's context menu", () => {
53 | var packetData = {
54 | "type": "fakeSentPacket",
55 | "to": "server1.conn1.child1/fakeActor2"
56 | };
57 | var data = {
58 | type: "send",
59 | id: 1,
60 | time: new Date("2015-06-09T16:48:50.162Z"),
61 | packet: packetData,
62 | size: JSON.stringify(packetData).length
63 | };
64 |
65 | var actions = {
66 | editPacket: jasmine.createSpy("editPacket"),
67 | selectPacket: jasmine.createSpy("selectPacket")
68 | };
69 |
70 | var packet = TestUtils.renderIntoDocument(Packet({
71 | showInlineDetails: false,
72 | data: data,
73 | actions: actions
74 | }));
75 |
76 | expect(packet.refs.contextMenu).not.toBeDefined();
77 |
78 | var el = ReactDOM.findDOMNode(packet);
79 | TestUtils.Simulate.contextMenu(el);
80 |
81 | // right clicking a packet opens a context menu and
82 | // select the packet
83 | expect(actions.selectPacket).toHaveBeenCalled();
84 | expect(packet.refs.contextMenu).toBeDefined();
85 | expect(packet.refs.editAndResendAction).toBeDefined();
86 |
87 | // clicking on the 'Edit and Resend' action
88 | var actionEl = ReactDOM.findDOMNode(packet.refs.editAndResendAction);
89 | TestUtils.Simulate.click(actionEl);
90 | expect(actions.editPacket).toHaveBeenCalled();
91 | });
92 | });
93 |
94 | describe("issues", () => {
95 | it("#44 - Long packet value breaks the view", () => {
96 | var data = {
97 | type: "receive",
98 | size: 0,
99 | id: 1,
100 | time: new Date("2015-06-09T16:48:50.162Z"),
101 | packet: {
102 | error: null,
103 | message: {
104 | "groupName": "",
105 | "columnNumber": 13,
106 | "lineNumber": 48,
107 | "workerType": "none",
108 | "level": "table",
109 | "counter": null,
110 | "arguments": [],
111 | "functionName": "onExecuteTest1"
112 | },
113 | "type": "consoleAPICall",
114 | "from": "server1.conn1.child1/consoleActor2"
115 | }
116 | };
117 |
118 | var packet = TestUtils.renderIntoDocument(Packet({
119 | showInlineDetails: false,
120 | data: data
121 | }));
122 |
123 | var el = ReactDOM.findDOMNode(packet);
124 |
125 | expect(el).toBeDefined();
126 |
127 | // NOTE: prior the fix, a long "consoleAPICall" received packet
128 | // was wrongly turned into a "div.errorMessage"
129 | var errorMessage = el.querySelector(".errorMessage");
130 | expect(errorMessage).toEqual(null);
131 | });
132 | });
133 |
134 | });
135 |
136 | });
137 |
--------------------------------------------------------------------------------
/data/inspector/components/packets-toolbar.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | var React = require("react");
9 |
10 | // Constants
11 | const {
12 | ButtonToolbar, Button,
13 | DropdownButton, MenuItem,
14 | OverlayTrigger, Tooltip
15 | } = require("shared/react-bootstrap-factories");
16 |
17 | const { span, input } = React.DOM;
18 |
19 | // RDP Window injected APIs
20 | const { Locale } = require("shared/rdp-inspector-window");
21 |
22 | /**
23 | * @template This object represents a template for a toolbar displayed
24 | * within the Packets tab
25 | */
26 | var PacketsToolbar = React.createClass({
27 | /** @lends PacketsToolbar */
28 |
29 | displayName: "PacketsToolbar",
30 |
31 | render: function() {
32 | var { showInlineDetails, packetCacheEnabled } = this.props;
33 |
34 | var labels = {};
35 | labels.inlineDetails = Locale.$STR("rdpInspector.option.showInlineDetails");
36 | labels.cachePackets = Locale.$STR("rdpInspector.option.packetCacheEnabled");
37 |
38 | var tooltips = {};
39 | tooltips.inlineDetails = Locale.$STR("rdpInspector.option.showInlineDetails.tip");
40 | tooltips.cachePackets = Locale.$STR("rdpInspector.option.packetCacheEnabled.tip");
41 |
42 | var paused = this.props.paused;
43 | var pauseClassName = paused ? "btn-warning" : "";
44 |
45 | return (
46 | ButtonToolbar({className: "toolbar"},
47 | DropdownButton({ bsSize: "xsmall", ref: "fileMenu", title: Locale.$STR("rdpInspector.menu.File")},
48 | MenuItem({key: "fileLoad", ref: "fileLoad", onClick: this.onLoadPacketsFromFile },
49 | Locale.$STR("rdpInspector.cmd.load")),
50 | MenuItem({key: "fileSave", ref: "fileSave", onClick: this.onSavePacketsFromFile },
51 | Locale.$STR("rdpInspector.cmd.save"))
52 | ),
53 | DropdownButton({
54 | bsSize: "xsmall", title: Locale.$STR("rdpInspector.menu.Options"),
55 | className: "pull-right", ref: "options"
56 | },
57 | OverlayTrigger({placement: "bottom", overlay: Tooltip({}, tooltips.inlineDetails)},
58 | MenuItem({key: "inlineDetails", ref: "optionShowInlineDetails", onClick: this.onShowInlineDetails},
59 | input({type: "checkbox", checked: showInlineDetails}), labels.inlineDetails
60 | )
61 | ),
62 | OverlayTrigger({placement: "bottom", overlay: Tooltip({}, tooltips.cachePackets)},
63 | MenuItem({key: "cachePackets", ref: "optionCachePackets", onClick: this.onCachePackets},
64 | input({type: "checkbox", checked: packetCacheEnabled}), labels.cachePackets
65 | )
66 | )
67 | ),
68 | Button({bsSize: "xsmall", onClick: this.onClear},
69 | Locale.$STR("rdpInspector.cmd.clear")
70 | ),
71 | Button({bsSize: "xsmall", onClick: this.onFind},
72 | Locale.$STR("rdpInspector.cmd.find")
73 | ),
74 | Button({bsSize: "xsmall", onClick: this.onSummary},
75 | Locale.$STR("rdpInspector.cmd.summary")
76 | ),
77 | Button({bsSize: "xsmall", className: pauseClassName,
78 | onClick: this.onPause},
79 | span({className: "glyphicon glyphicon-pause", "aria-hidden": true})
80 | )
81 | )
82 | );
83 | },
84 |
85 | // Commands
86 |
87 | onClear: function(/*event*/) {
88 | this.props.actions.clear();
89 | },
90 |
91 | onFind: function(/*event*/) {
92 | this.props.actions.find();
93 | },
94 |
95 | onSummary: function(/*event*/) {
96 | this.props.actions.appendSummary();
97 | },
98 |
99 | onShowInlineDetails: function() {
100 | this.props.actions.onShowInlineDetails();
101 | },
102 |
103 | onCachePackets: function() {
104 | this.props.actions.onPacketCacheEnabled();
105 | },
106 |
107 | onPause: function(/*event*/) {
108 | this.props.actions.onPause();
109 | },
110 |
111 | onLoadPacketsFromFile: function(/*event*/) {
112 | this.props.actions.loadPacketsFromFile();
113 | this.refs.fileMenu.setState({ open: false });
114 |
115 | },
116 |
117 | onSavePacketsFromFile: function(/*event*/) {
118 | this.props.actions.savePacketsToFile();
119 | this.refs.fileMenu.setState({ open: false });
120 | }
121 | });
122 |
123 | // Exports from this module
124 | exports.PacketsToolbar = React.createFactory(PacketsToolbar);
125 | exports.PacketsToolbarComponent = PacketsToolbar;
126 | });
127 |
--------------------------------------------------------------------------------
/data/inspector/components/packet-editor.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Dependencies
8 | const React = require("react");
9 |
10 | // Firebug SDK
11 | const { TreeEditorView } = require("./tree-editor-view");
12 |
13 | // Constants
14 | const { div } = React.DOM;
15 |
16 | const { ButtonToolbar, Button } = require("shared/react-bootstrap-factories");
17 |
18 | /**
19 | * @template This template represents the Packet Editor toolbar
20 | */
21 |
22 | var PacketEditorToolbar = React.createFactory(React.createClass({
23 | /** @lends PacketEditrView */
24 |
25 | displayName: "PacketEditorToolbar",
26 |
27 | render: function() {
28 | return ButtonToolbar({className: "toolbar"}, [
29 | Button({ onClick: this.props.onSend, key: "send",
30 | bsStyle: "primary", bsSize: "xsmall",
31 | style: { marginLeft: 12, color: "white" } }, "Send"),
32 |
33 | Button({ onClick: this.props.onRedo, key: "redo",
34 | className: "pull-right",
35 | disabled: !this.props.isRedoEnabled,
36 | bsStyle: "default", bsSize: "xsmall",
37 | style: { marginRight: 6 } }, "Redo"),
38 | Button({ onClick: this.props.onUndo, key: "undo",
39 | className: "pull-right",
40 | disabled: !this.props.isUndoEnabled,
41 | bsStyle: "default", bsSize: "xsmall",
42 | style: { marginRight: 6 } }, "Undo"),
43 | Button({ onClick: this.props.onClear, key: "clear",
44 | className: "pull-right",
45 | bsStyle: "danger", bsSize: "xsmall",
46 | style: { marginRight: 6, color: "white" } }, "Clear")
47 | ]);
48 | }
49 | }));
50 |
51 | /**
52 | * @template This template represents the PacketEditor sidebar
53 | */
54 | var PacketEditor = React.createClass({
55 | displayName: "PacketEditor",
56 |
57 | getInitialState: function() {
58 | return {
59 | editedPacket: null,
60 | defaultData: {
61 | to: "root",
62 | type: "requestTypes"
63 | }
64 | };
65 | },
66 |
67 | componentWillReceiveProps: function(nextProps) {
68 | this.setState({
69 | editedPacket: nextProps.editedPacket
70 | });
71 | },
72 |
73 | render: function() {
74 | var editedPacket = this.state.editedPacket || this.props.editedPacket;
75 | var { actorIDs } = this.props;
76 |
77 | return (
78 | div({className: "details editor"},
79 | PacketEditorToolbar({
80 | onClear: this.onClear,
81 | onSend: this.onSend,
82 | onUndo: this.onUndo,
83 | onRedo: this.onRedo,
84 | isUndoEnabled: true,
85 | isRedoEnabled: true
86 | }),
87 | TreeEditorView({
88 | ref: "editor",
89 | key: "packet-editor",
90 | data: editedPacket,
91 | defaultData: this.state.defaultData,
92 | handleAutocompletion: (suggestionType, keyPath, value) => {
93 | if (!actorIDs && suggestionType != "value") {
94 | return [];
95 | }
96 |
97 | try {
98 | var parsedValue;
99 |
100 | // remove starting and ending '"' if any
101 | parsedValue = typeof value == "string" ?
102 | value.replace(/^"|"$/g, "") : "";
103 |
104 | if(keyPath.length == 1 && keyPath[0] == "to") {
105 | // get a suggestion list by filtering actorIDs list
106 | return actorIDs.filter((suggestion) => {
107 | return suggestion.indexOf(parsedValue) >= 0;
108 | });
109 | }
110 | } catch(e) {
111 | //console.debug("exception on parsing autocompletion", e);
112 | }
113 |
114 | return [];
115 | }
116 | })
117 | )
118 | );
119 | },
120 |
121 | onUndo: function() {
122 | this.refs.editor.undo();
123 | },
124 |
125 | onRedo: function() {
126 | this.refs.editor.redo();
127 | },
128 |
129 | onClear: function() {
130 | this.refs.editor.clearData();
131 | },
132 |
133 | onSend: function() {
134 | this.props.actions.send(this.refs.editor.getData());
135 | }
136 | });
137 |
138 | // Exports from this module
139 | exports.PacketEditor = React.createFactory(PacketEditor);
140 |
141 | });
142 |
--------------------------------------------------------------------------------
/data/inspector/components/stack-frame-rep.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports /*, module */) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | const React = require("react");
9 |
10 | // Firebug SDK
11 | const { Reps } = require("reps/reps");
12 | const { ObjectBox } = require("reps/object-box");
13 |
14 | // Constants
15 | const { span } = React.DOM;
16 |
17 | // RDP Window injected APIs
18 | const { postChromeMessage } = require("shared/rdp-inspector-window");
19 |
20 | /**
21 | * This component is responsible for rendering a stack frame.
22 | */
23 | var StackFrameRep = React.createClass({
24 | /** @lends StackFrameRep */
25 |
26 | displayName: "StackFrameRep",
27 |
28 | render: function() {
29 | var stackFrame = this.props.object;
30 | var name = stackFrame.name;
31 | var label = stackFrame.getLabel();
32 |
33 | return (
34 | ObjectBox({className: "stackFrame"},
35 | span({className: "stackName"}, name + "()"),
36 | span({className: "stackLabel", onClick: this.onViewSource}, label)
37 | )
38 | );
39 | },
40 |
41 | onViewSource: function(event) {
42 | event.stopPropagation();
43 | event.preventDefault();
44 |
45 | // xxxHonza: how to get reference to the action list?
46 | /*this.props.actions.onViewSource({
47 | url: topFrame.fileName,
48 | lineNumber: topFrame.lineNumber
49 | });*/
50 |
51 | var frame = this.props.object;
52 | postChromeMessage("view-source", {
53 | url: frame.url,
54 | lineNumber: frame.lineNumber
55 | });
56 | }
57 | });
58 |
59 | // Registration
60 |
61 | function supportsObject(object/*, type*/) {
62 | return object instanceof StackFrame;
63 | }
64 |
65 | Reps.registerRep({
66 | rep: React.createFactory(StackFrameRep),
67 | supportsObject: supportsObject
68 | });
69 |
70 | // helper classes using in the packets reducers
71 |
72 | // StackTrace
73 |
74 | // xxxHonza: revisit frame filtering should and find solid way.
75 | function StackTrace(frames, packetType) {
76 | // Remove all frames before 'EventEmitter_emit()' frame.
77 | // These are part of the infrastructure (always there).
78 | if (packetType == "send") {
79 | //frames = filterFrames(frames, "DebuggerClient.requester/<");
80 | //frames = filterFrames(frames, "EventEmitter_emit");
81 | //frames = filterFrames(frames, "makeInfallible/<", true);
82 | }
83 |
84 | // Filter out empty frames
85 | frames = frames.filter(frame => !!frame.name);
86 |
87 | // Create StackFrame instances, so the right rep is used for
88 | // rendering (see {@StackFrameRep}.
89 | this.frames = frames.map(frame => new StackFrame(frame));
90 | }
91 |
92 | StackTrace.prototype = {
93 | hasFrames: function() {
94 | return this.frames.length > 0;
95 | },
96 |
97 | getTopFrame: function() {
98 | return this.hasFrames() ? this.frames[0] : null;
99 | },
100 | };
101 |
102 | // StackFrame
103 |
104 | function StackFrame(frame) {
105 | this.url = frame.fileName;
106 | this.lineNumber = frame.lineNumber;
107 | this.columnNumber = frame.columnNumber;
108 | this.name = frame.name;
109 | }
110 |
111 | StackFrame.prototype = {
112 | getLabel: function() {
113 | var path = this.url;
114 | var index = path ? path.lastIndexOf("/") : -1;
115 | var label = (index == -1) ? path : path.substr(index + 1);
116 |
117 | if (this.lineNumber) {
118 | label += ":" + this.lineNumber;
119 | }
120 |
121 | if (this.columnNumber) {
122 | label += ":" + this.columnNumber;
123 | }
124 |
125 | return label;
126 | },
127 |
128 | getUrl: function() {
129 | return this.url;
130 | }
131 | };
132 |
133 | // Helpers
134 |
135 | /* NOTE: currently unused */
136 | /*
137 | function filterFrames(frames, pivot, onlyFirst) {
138 | var frame;
139 |
140 | if (onlyFirst) {
141 | for (frame of frames) {
142 | if (frame.name == pivot) {
143 | frames.shift();
144 | } else {
145 | break;
146 | }
147 | }
148 | return frames;
149 | }
150 |
151 | var newFrames = [];
152 | var remove = true;
153 | for (frame of frames) {
154 | if (!remove) {
155 | newFrames.push(frame);
156 | }
157 |
158 | if (frame.name == pivot) {
159 | remove = false;
160 | }
161 | }
162 |
163 | // The pivot frame wasn't found.
164 | if (remove) {
165 | newFrames = frames;
166 | }
167 |
168 | return newFrames;
169 | }
170 | */
171 |
172 |
173 | // Exports from this module
174 | exports.StackFrameRep = StackFrameRep;
175 | exports.StackTrace = StackTrace;
176 | exports.StackFrame = StackFrame;
177 |
178 | });
179 |
--------------------------------------------------------------------------------
/lib/toolbox-overlay.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | "use strict";
4 |
5 | module.metadata = {
6 | "stability": "stable"
7 | };
8 |
9 | // Add-on SDK
10 | const { components } = require("chrome");
11 | const { Class } = require("sdk/core/heritage");
12 | const simplePrefs = require("sdk/simple-prefs");
13 | const { prefs } = simplePrefs;
14 |
15 | // Firebug SDK
16 | const { Trace/*, TraceError*/ } = require("firebug.sdk/lib/core/trace.js").get(module.id);
17 | /*const { Locale } = require("firebug.sdk/lib/core/locale.js");*/
18 | const { ToolboxOverlay: ToolboxOverlayBase } = require("firebug.sdk/lib/toolbox-overlay.js");
19 | const { TransportObserver } = require("./transport-observer.js");
20 | const { Arr } = require("firebug.sdk/lib/core/array.js");
21 | const { Options } = require("firebug.sdk/lib/core/options.js");
22 |
23 | // RDP Inspector
24 | const { InspectorWindow } = require("./inspector-window.js");
25 |
26 | /**
27 | * @overlay xxxHonza: TODO docs
28 | */
29 | const ToolboxOverlay = Class(
30 | /** @lends ToolboxOverlay */
31 | {
32 | extends: ToolboxOverlayBase,
33 |
34 | overlayId: "RdpInspectorToolboxOverlay",
35 |
36 | packetCache: null,
37 | listeners: [],
38 |
39 | // Initialization
40 |
41 | initialize: function(options) {
42 | ToolboxOverlayBase.prototype.initialize.apply(this, arguments);
43 |
44 | Trace.sysout("ToolboxOverlay.initialize;", options);
45 |
46 | // handler of packetCache toggling
47 | this.onToggleCache = this.onToggleCache.bind(this);
48 |
49 | // set initial value
50 | this.onToggleCache();
51 |
52 | // register for prefs change
53 | simplePrefs.on("packetCacheEnabled", this.onToggleCache);
54 |
55 | // Transport Protocol
56 | this.onSendPacket = this.onSendPacket.bind(this);
57 | this.onReceivePacket = this.onReceivePacket.bind(this);
58 |
59 | // Initialize transport observer
60 | this.toolbox.target.makeRemote();
61 | let client = this.toolbox.target.client;
62 | this.transportObserver = new TransportObserver({client: client});
63 | this.transportObserver.addListener(this);
64 |
65 | // Number of removed packets from the cache that are out of limit.
66 | this.removedPackets = 0;
67 | },
68 |
69 | destroy: function() {
70 | ToolboxOverlayBase.prototype.destroy.apply(this, arguments);
71 |
72 | Trace.sysout("ToolboxOverlay.destroy;", arguments);
73 |
74 | simplePrefs.off("packetCacheEnabled", this.onToggleCache);
75 |
76 | if (this.transportObserver) {
77 | this.removeTransportListener(this);
78 | this.transportObserver.destroy();
79 | }
80 |
81 | if (this.inspector) {
82 | this.inspector.destroy();
83 | }
84 | },
85 |
86 | // Events
87 |
88 | onReady: function(options) {
89 | ToolboxOverlayBase.prototype.onReady.apply(this, arguments);
90 |
91 | Trace.sysout("ToolboxOverlay.onReady;", options);
92 | },
93 |
94 | onToggleCache: function() {
95 | this.packetCache = prefs.packetCacheEnabled ? [] : null;
96 | },
97 |
98 | // Transport Listener
99 |
100 | getPacketCache: function() {
101 | return {
102 | removedPackets: this.removedPackets,
103 | packets: this.packetCache
104 | };
105 | },
106 |
107 | addTransportListener: function(listener) {
108 | this.listeners.push(listener);
109 |
110 | // Stop caching as soon as the first listener is registered.
111 | // It's the {@InspectorWindow} object that is listening to
112 | // sent/received packets. The listener is added as soon as
113 | // the window is initialized.
114 | this.packetCache = null;
115 | },
116 |
117 | removeTransportListener: function(listener) {
118 | Arr.remove(this.listeners, listener);
119 | },
120 |
121 | onSendPacket: function(packet) {
122 | var data = {
123 | type: "send",
124 | packet: packet,
125 | time: (new Date()).getTime(),
126 | stack: this.getStack()
127 | };
128 |
129 | this.appendPacket(data);
130 |
131 | this.listeners.forEach(listener => {
132 | listener.onSendPacket(data);
133 | });
134 | },
135 |
136 | onReceivePacket: function(packet) {
137 | var data = {
138 | type: "receive",
139 | packet: packet,
140 | time: (new Date()).getTime(),
141 | stack: this.getStack()
142 | };
143 |
144 | this.appendPacket(data);
145 |
146 | this.listeners.forEach(listener => {
147 | listener.onReceivePacket(data);
148 | });
149 | },
150 |
151 | appendPacket: function(packet) {
152 | if (!this.packetCache) {
153 | return;
154 | }
155 |
156 | try {
157 | this.packetCache.push(packet);
158 | } catch (err) {
159 | Trace.sysout("ToolboxOverlay.appendPacket; ERROR" + err, err);
160 |
161 | // xxxHonza: create a new packet that displays an error in the
162 | // packet list UI.
163 | // this.packetCache.push({...});
164 | return;
165 | }
166 |
167 | var limit = Options.getPref("extensions.rdpinspector.packetCacheSize");
168 | while (this.packetCache.length > limit) {
169 | this.packetCache.shift();
170 | this.removedPackets++;
171 | }
172 | },
173 |
174 | getStack: function() {
175 | var frames = [];
176 | var stack = components.stack;
177 | while (stack) {
178 | frames.push({
179 | name: stack.name,
180 | lineNumber: stack.lineNumber,
181 | columnNumber: stack.columnNumber,
182 | fileName: stack.filename
183 | });
184 | stack = stack.asyncCaller || stack.caller;
185 | }
186 | return frames;
187 | },
188 |
189 | // Commands
190 |
191 | openInspectorWindow: function(inspectorWindowName) {
192 | Trace.sysout("ToolboxOverlay.toggleInspector;");
193 |
194 | if (!this.inspector) {
195 | this.inspector = new InspectorWindow(this, inspectorWindowName);
196 | }
197 |
198 | // Show or hide the popup panel.
199 | this.inspector.open();
200 |
201 | return this.inspector;
202 | }
203 | });
204 |
205 | // Exports from this module
206 | exports.ToolboxOverlay = ToolboxOverlay;
207 |
--------------------------------------------------------------------------------
/lib/connection-list-window.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | "use strict";
4 |
5 | module.metadata = {
6 | "stability": "experimental"
7 | };
8 |
9 | // Add-on SDK
10 | const { data } = require("sdk/self");
11 | /*const options = require("@loader/options");*/
12 | const { Class } = require("sdk/core/heritage");
13 | const { openDialog, getMostRecentWindow } = require("sdk/window/utils");
14 | const Events = require("sdk/dom/events");
15 | const { Cu } = require("chrome");
16 |
17 | // Firebug SDK
18 | const { Trace, TraceError } = require("firebug.sdk/lib/core/trace.js").get(module.id);
19 | const { Locale } = require("firebug.sdk/lib/core/locale.js");
20 | const { Content } = require("firebug.sdk/lib/core/content.js");
21 | const { Str } = require("firebug.sdk/lib/core/string.js");
22 | const { Options } = require("firebug.sdk/lib/core/options.js");
23 | const { Dispatcher } = require("firebug.sdk/lib/dispatcher.js");
24 |
25 | // Constants
26 | const { InspectorService } = require("./inspector-service.js");
27 |
28 | const WINDOW_TYPE = "RDPInspectorConnectionList";
29 | const CONNECTIONS_XUL_URL = "chrome://rdpinspector/content/connections-window.xul";
30 |
31 | /**
32 | * This class manages the connections list window
33 | */
34 | const ConnectionListWindow = Class(
35 | /** @lends ConnectionListWindow */
36 | {
37 | initialize() {
38 | // TODO: bind event handling methods
39 |
40 | // DOM Events
41 | this.onClose = this.onClose.bind(this);
42 | this.onLoad = this.onLoad.bind(this);
43 | this.onFrameContentLoaded = this.onFrameContentLoaded.bind(this);
44 |
45 | // Content callbacks
46 | this.connectionsUpdatedListeners = new Set();
47 |
48 | // Dispatcher events
49 | this.onRDPConnectionsUpdated = this.onRDPConnectionsUpdated.bind(this);
50 |
51 | Dispatcher.on("onRDPConnectionsUpdated", this.onRDPConnectionsUpdated);
52 | },
53 |
54 | destroy() {
55 | // TODO: cleanup (e.g. close the connection list window)
56 |
57 | // Content callbacks
58 | this.connectionsUpdatedListeners.clear();
59 |
60 | // Dispatcher events
61 | Dispatcher.off("onRDPConnectionsUpdated", this.onRDPConnectionsUpdated);
62 | },
63 |
64 | open() {
65 | Trace.sysout("ConnectionListWindow.open;", arguments);
66 |
67 | // If the Connections List window is already opened, focus and return it.
68 | let win = getMostRecentWindow(WINDOW_TYPE);
69 |
70 | if (win) {
71 | win.focus();
72 | return win;
73 | }
74 |
75 | return this._open("rdp-inspector-connections", CONNECTIONS_XUL_URL, [{}]);
76 | },
77 |
78 | _open(windowType, url, params) {
79 | Trace.sysout("ConnectionListWindow.open;", arguments);
80 |
81 | // Open RDP Inspector console window.
82 | this.win = openDialog({
83 | url: url,
84 | name: WINDOW_TYPE,
85 | args: params,
86 | features: "chrome,resizable,scrollbars=auto,minimizable,dialog=no"
87 | });
88 |
89 | // Hook events
90 | Events.on(this.win, "load", this.onLoad);
91 | Events.on(this.win, "close", this.onClose);
92 |
93 | return this.win;
94 | },
95 |
96 | // Event Handlers
97 |
98 | onLoad(event) {
99 | Trace.sysout("ConnectionListWindow.onLoad; ", event);
100 |
101 | let frame = this.getFrame();
102 | frame.setAttribute("src", data.url("connection-list/index.html"));
103 |
104 | Events.once(frame, "DOMContentLoaded", this.onFrameContentLoaded);
105 | },
106 |
107 | onFrameContentLoaded(event) {
108 | Trace.sysout("ConnectionListWindow.onFrameContentLoaded; ", event);
109 |
110 | let contentWindow = this.getContentWindow();
111 |
112 | let { Trace: contentTrace } = FBTrace.get("CONTENT");
113 | Content.exportIntoContentScope(contentWindow, Str, "Str");
114 | Content.exportIntoContentScope(contentWindow, Locale, "Locale");
115 | Content.exportIntoContentScope(contentWindow, contentTrace, "Trace");
116 | Content.exportIntoContentScope(contentWindow, TraceError, "TraceError");
117 | Content.exportIntoContentScope(contentWindow, Options, "Options");
118 |
119 | this.exportCustomContentAPI(contentWindow);
120 | },
121 |
122 | exportCustomContentAPI(contentWindow) {
123 | var contentAPI = Cu.createObjectIn(contentWindow, {
124 | defineAs: "RDPConnectionList"
125 | });
126 |
127 | Cu.exportFunction(function getConnectionsInfo() {
128 | let connectionsInfo = InspectorService.getConnectionsInfo();
129 |
130 | return Cu.cloneInto(connectionsInfo, contentWindow);
131 | }, contentAPI, {
132 | defineAs: "getConnectionsInfo"
133 | });
134 |
135 | Cu.exportFunction(function openRDPInspectorWindow(conn) {
136 | InspectorService.openRDPInspectorWindow(conn.uuid);
137 | }, contentAPI, {
138 | defineAs: "openRDPInspectorWindow"
139 | });
140 |
141 | var onConnectionsUpdated = Cu.createObjectIn(contentAPI, {
142 | defineAs: "onConnectionsUpdated"
143 | });
144 |
145 | Cu.exportFunction((cb) => {
146 | this.connectionsUpdatedListeners.add(cb);
147 | }, onConnectionsUpdated, { allowCallbacks: true, defineAs: "addListener" });
148 |
149 | Cu.exportFunction((cb) => {
150 | this.connectionsUpdatedListeners.delete(cb);
151 | }, onConnectionsUpdated, { allowCallbacks: true, defineAs: "removeListener" });
152 | },
153 |
154 | onRDPConnectionsUpdated() {
155 | let contentWindow = this.getContentWindow();
156 | let connectionsInfo = InspectorService.getConnectionsInfo();
157 |
158 | let contentConnInfo = Cu.cloneInto(connectionsInfo, contentWindow);
159 |
160 | for (let cb of this.connectionsUpdatedListeners) {
161 | try {
162 | cb(contentConnInfo);
163 | } catch(e) {
164 | TraceError.sysout("ConnectionListWindow.onRDPConnectionsUpdated; ERROR in content cb: " + e);
165 | }
166 | }
167 | },
168 |
169 | onClose(event) {
170 | Trace.sysout("ConnectionListWindow.onClose; " + event, arguments);
171 |
172 | this.win = null;
173 | },
174 |
175 | getContentWindow: function() {
176 | let frame = this.getFrame();
177 | if (!frame) {
178 | return null;
179 | }
180 |
181 | return frame && frame.contentWindow;
182 | },
183 |
184 | getFrame: function() {
185 | if (!this.win) {
186 | return null;
187 | }
188 |
189 | return this.win.document.getElementById("contentFrame");
190 | }
191 | });
192 |
193 | // Exports from this module
194 | exports.ConnectionListWindow = ConnectionListWindow;
195 |
--------------------------------------------------------------------------------
/data/inspector/css/packets-panel.css:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | /******************************************************************************/
4 | /* Packets Panel */
5 |
6 | .packetPanel {
7 | margin-bottom: 6px;
8 | font-size: 11px;
9 | font-family: Lucida Grande, Tahoma, sans-serif;
10 | line-height: 15px;
11 | }
12 |
13 | .packetPanel .packetBox {
14 | display: inline-block;
15 | max-width: 90%;
16 | }
17 |
18 | .packetPanel .packetContent {
19 | display: flex;
20 | }
21 |
22 | .packetPanel.receive .boxArrow {
23 | background-image: url("../res/received-arrow.png");
24 | background-repeat: no-repeat;
25 | background-position: 0 center;
26 | margin-right: -1px;
27 | order: 1;
28 | width: 8px;
29 | z-index: 2;
30 | min-width: 8px;
31 | }
32 |
33 | .packetPanel.receive.selected .boxArrow {
34 | background-image: url("../res/received-arrow-selected.png");
35 | }
36 |
37 | .packetPanel.send .boxArrow {
38 | background-image: url("../res/sent-arrow.png");
39 | background-repeat: no-repeat;
40 | background-position: 0 center;
41 | margin-left: -1px;
42 | order: 3;
43 | width: 9px;
44 | min-width: 9px;
45 | z-index: 2;
46 | }
47 |
48 | .packetPanel.send.selected .boxArrow {
49 | background-image: url("../res/sent-arrow-selected.png");
50 | }
51 |
52 | .packetPanel .body {
53 | display: inline-block;
54 | padding: 2px 5px 2px 5px;
55 | border: 1px solid #bfccd1;
56 | border-radius: 3px;
57 | min-width: 270px;
58 | background-image: linear-gradient(rgba(255, 255, 255, 0.7), rgba(255, 255, 255, 0.0));
59 | order: 2;
60 | z-index: 1;
61 | }
62 |
63 | .packetPanel.receive .body {
64 | background-color: rgb(252, 248, 227);
65 | }
66 |
67 | .packetPanel.send .body {
68 | background-color: rgb(223, 240, 216);
69 | text-align: left;
70 | }
71 |
72 | .packetPanel.send {
73 | text-align: left;
74 | }
75 |
76 | .packetPanel.send {
77 | text-align: right;
78 | }
79 |
80 | .packetPanel .body .text {
81 | color: gray;
82 | }
83 |
84 | .packetPanel.error .body {
85 | background-color: rgb(255, 221, 221);
86 | }
87 |
88 | .packetPanel.selected .body {
89 | border-color: rgb(0, 170, 214);
90 | background-color: rgb(173, 211, 232);
91 | }
92 |
93 | .packetPanel .type,
94 | .packetPanel .to,
95 | .packetPanel .from {
96 | color: red;
97 | font-family: monospace;
98 | }
99 |
100 | .packetPanel .info {
101 | color: gray;
102 | font-size: 10px;
103 | text-align: right;
104 | margin-left: 20px;
105 | display: inline-flex;
106 | font-family: monospace;
107 | float: right;
108 | padding-top: 4px;
109 | }
110 |
111 | .packetPanel .stack:hover {
112 | text-decoration: underline;
113 | }
114 |
115 | .packetPanel .arrow {
116 | margin: 0 5px 0 5px;
117 | }
118 |
119 | .packetPanel .arrow.hide {
120 | display: none;
121 | }
122 | .packetPanel .from {
123 | padding-bottom: 5px;}
124 |
125 | .packetPanel .errorMessage {
126 | color: red;
127 | margin-bottom: 5px;
128 | }
129 |
130 | /******************************************************************************/
131 | /* Inline Packet Details Preview */
132 |
133 | .packetPanel .preview {
134 | overflow: auto;
135 | width: 100%;
136 | }
137 |
138 | .packetPanel .memberRow:hover {
139 | background-color: transparent;
140 | }
141 |
142 | .packetPanel .domTable > tbody > tr > td {
143 | border-bottom: transparent;
144 | }
145 |
146 | /******************************************************************************/
147 |
148 | .packetsPanelBox {
149 | height: 100%;
150 | }
151 |
152 | .packetsPanelBox TD {
153 | vertical-align: top;
154 | }
155 |
156 | .packetsPanelBox .list {
157 | /* xxxHonza: minus the toolbar height*/
158 | height: calc(100% - 30px);
159 | overflow: auto;
160 | padding: 10px;
161 | }
162 |
163 | .packetsPanelBox .details {
164 | border-left: 1px solid #EFEFEF;
165 | height: 100%;
166 | overflow: auto;
167 | }
168 |
169 | .tabPacketsPane {
170 | height: 100%;
171 | padding: 0px;
172 | }
173 |
174 | /******************************************************************************/
175 | /* Packets Summary */
176 |
177 | .packetsSummary {
178 | color: gray;
179 | font-size: 10px;
180 | border-top: 1px dotted #EFEFEF;
181 | margin: 10px 0 20px 0;
182 | padding: 2px 0 2px 0;
183 | }
184 |
185 | .packetsSummary DIV {
186 | display: inline-block;
187 | }
188 |
189 | .packetsSummary .time {
190 | float: right;
191 | font-family: monospace;
192 | }
193 |
194 | .packetsSummary .separator {
195 | width: 20px;
196 | }
197 |
198 | .packetsSummary .text {
199 | padding-right: 3px;
200 | }
201 |
202 | .packetsSummary .slash {
203 | width: 10px;
204 | text-align: center;
205 | }
206 |
207 | .tooltip-inner {
208 | max-width: 110px;
209 | }
210 |
211 | /******************************************************************************/
212 | /* Packets Limit */
213 |
214 | .packetsLimit {
215 | text-align: center;
216 | margin: 10px 0 20px 0;
217 | }
218 |
219 | .packetsLimit .text {
220 | padding: 2px 3px 2px 3px;
221 | color: gray;
222 | font-size: 12px;
223 | border: 1px solid #bfccd1;
224 | border-radius: 3px;
225 | background-color: rgb(219, 234, 249) !important;
226 | background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.2));
227 | }
228 |
229 | /******************************************************************************/
230 | /* Packets Message */
231 |
232 | .packetsMessage {
233 | color: gray;
234 | font-size: 10px;
235 | border-top: 1px dotted #EFEFEF;
236 | margin: 10px 0 20px 0;
237 | padding: 2px 0 2px 0;
238 | }
239 |
240 | .packetsMessage DIV {
241 | display: inline-block;
242 | }
243 |
244 | .packetsMessage .time {
245 | float: right;
246 | font-family: monospace;
247 | }
248 |
249 | .packetsMessage .text {
250 | padding-right: 3px;
251 | }
252 |
253 | /******************************************************************************/
254 | /* StackFrame */
255 |
256 | .stackSidePanel {
257 | height: 100%;
258 | overflow: auto;
259 | }
260 |
261 | .stackSidePanel .preview {
262 | overflow: auto;
263 | width: 100%;
264 | }
265 |
266 | .stackSidePanel .objectBox-stackFrame .stackName {
267 | display: inline-flex;
268 | font-family: monospace;
269 | float: left;
270 | text-align: left;
271 | }
272 |
273 | .packetPanel .stackFrameLabel,
274 | .stackSidePanel .objectBox-stackFrame .stackLabel {
275 | color: blue;
276 | text-align: right;
277 | display: inline-flex;
278 | font-family: monospace;
279 | float: right;
280 | cursor: pointer;
281 | margin-right: 4px;
282 | }
283 |
284 | .packetPanel .stackFrameLabel {
285 | font-size: 10px;
286 | margin-top: 4px;
287 | float: left;
288 | }
289 |
--------------------------------------------------------------------------------
/lib/inspector-actor.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | "use strict";
4 |
5 | // Add-on SDK
6 | const { Cu } = require("chrome");
7 |
8 | /**
9 | * Allows importing a JS module (Firefox platform) and specify alternative locations
10 | * to keep backward compatibility in case when the module location changes.
11 | * It helps Firebug to support multiple Firefox versions.
12 | *
13 | * @param {Array} locations List of URLs to try when importing the module.
14 | * @returns Scope of the imported module or an empty scope if module wasn't successfully loaded.
15 | */
16 | function safeImport(...args) {
17 | for (var i = 0; i < args.length; i++) {
18 | try {
19 | return Cu["import"](args[i], {});
20 | }
21 | /* eslint-disable */
22 | catch (err) {
23 | }
24 | /* eslint-enable */
25 | }
26 | return {};
27 | }
28 |
29 | function safeRequire(devtoolsLoader, ...args) {
30 | for (var i = 0; i < args.length; i++) {
31 | try {
32 | return devtoolsLoader["require"](args[i]);
33 | }
34 | /* eslint-disable */
35 | catch (err) {
36 | }
37 | /* eslint-enable */
38 | }
39 | return {};
40 | }
41 |
42 | // DevTools
43 | // See also:
44 | // - https://bugzilla.mozilla.org/show_bug.cgi?id=912121
45 | // - https://bugzilla.mozilla.org/show_bug.cgi?id=1203159
46 | const devtools = safeImport(
47 | "resource://devtools/shared/Loader.jsm",
48 | "resource://gre/modules/devtools/shared/Loader.jsm",
49 | "resource://gre/modules/devtools/Loader.jsm"
50 | ).devtools;
51 |
52 | const protocol = safeRequire(devtools,
53 | "devtools/shared/protocol",
54 | "devtools/server/protocol"
55 | );
56 |
57 | const { DebuggerServer } = devtools["require"]("devtools/server/main");
58 | const { method, RetVal, ActorClass, Actor } = protocol;
59 |
60 | // For debugging purposes. Note that the tracing module isn't available
61 | // on the backend (in case of remote device debugging).
62 | // const baseUrl = "resource://rdpinspector-at-getfirebug-dot-com/";
63 | // const { getTrace } = Cu.import(baseUrl + "node_modules/firebug.sdk/lib/core/actor.js");
64 | // const Trace = getTrace();
65 | const Trace = {sysout: () => {}};
66 |
67 | function dumpFactories(factories) {
68 | let result = [];
69 |
70 | let props = Object.getOwnPropertyNames(factories);
71 | for (let name of props) {
72 | let factory = factories[name];
73 | result.push({
74 | name: factory.name,
75 | prefix: factory._prefix,
76 | constructor: factory.constructor ? factory.constructor.name : undefined
77 | });
78 | }
79 |
80 | return result;
81 | }
82 |
83 | /**
84 | * Helper actor state watcher.
85 | */
86 | function expectState(expectedState, calledMethod) {
87 | return function(...args) {
88 | if (this.state !== expectedState) {
89 | Trace.sysout("actor.expectState; ERROR wrong state, expected '" +
90 | expectedState + "', but current state is '" + this.state + "'" +
91 | ", method: " + calledMethod);
92 |
93 | let msg = "Wrong State: Expected '" + expectedState + "', but current " +
94 | "state is '" + this.state + "'";
95 |
96 | return Promise.reject(new Error(msg));
97 | }
98 |
99 | try {
100 | return calledMethod.apply(this, args);
101 | } catch (err) {
102 | Cu.reportError("actor.js; expectState EXCEPTION " + err, err);
103 | }
104 | };
105 | }
106 |
107 | /**
108 | * @actor TODO docs
109 | */
110 | var InspectorActor = ActorClass(
111 | /** @lends InspectorActor */
112 | {
113 | typeName: "actorInspector",
114 |
115 | // Initialization
116 |
117 | initialize: function(conn, parent) {
118 | Trace.sysout("InspectorActor.initialize; parent: " +
119 | parent.actorID + ", conn: " + conn.prefix, this);
120 |
121 | Actor.prototype.initialize.call(this, conn);
122 |
123 | this.parent = parent;
124 | this.state = "detached";
125 | },
126 |
127 | /**
128 | * The destroy is only called automatically by the framework (parent actor)
129 | * if an actor is instantiated by a parent actor.
130 | */
131 | destroy: function() {
132 | Trace.sysout("InspectorActor.destroy; state: " + this.state, arguments);
133 |
134 | if (this.state === "attached") {
135 | this.detach();
136 | }
137 |
138 | Actor.prototype.destroy.call(this);
139 | },
140 |
141 | /**
142 | * Automatically executed by the framework when the parent connection
143 | * is closed.
144 | */
145 | disconnect: function() {
146 | Trace.sysout("InspectorActor.disconnect; state: " + this.state, arguments);
147 |
148 | if (this.state === "attached") {
149 | this.detach();
150 | }
151 | },
152 |
153 | /**
154 | * Attach to this actor. Executed when the front (client) is attaching
155 | * to this actor.
156 | */
157 | attach: method(expectState("detached", function() {
158 | Trace.sysout("monitorActor.attach;", arguments);
159 |
160 | this.state = "attached";
161 | }), {
162 | request: {},
163 | response: {
164 | type: "attached"
165 | }
166 | }),
167 |
168 | /**
169 | * Detach from this actor. Executed when the front (client) detaches
170 | * from this actor.
171 | */
172 | detach: method(expectState("attached", function() {
173 | Trace.sysout("monitorActor.detach;", arguments);
174 |
175 | this.state = "detached";
176 | }), {
177 | request: {},
178 | response: {
179 | type: "detached"
180 | }
181 | }),
182 |
183 | // Actor API
184 |
185 | /**
186 | * A test remote method.
187 | */
188 | getActors: method(expectState("attached", function() {
189 | let result = {};
190 |
191 | Trace.sysout("inspectorActor.getActors; connection ", this.conn);
192 |
193 | // Get actor pools (instances)
194 | if (this.conn._actorPool) {
195 | result.actorPool = {
196 | pool: dumpPool(this.conn._actorPool),
197 | id: this.conn._actorPool.id
198 | };
199 | }
200 |
201 | result.extraPools = [];
202 |
203 | for (let pool of this.conn._extraPools) {
204 | if (pool !== this.conn._actorPool) {
205 | result.extraPools.push({
206 | pool: dumpPool(pool),
207 | id: pool.id
208 | });
209 | }
210 | }
211 |
212 | // Get actor factories (classes)
213 | result.factories = {};
214 | result.factories.global = dumpFactories(DebuggerServer.globalActorFactories);
215 | result.factories.tab = dumpFactories(DebuggerServer.tabActorFactories);
216 |
217 | return result;
218 | }), {
219 | request: {},
220 | response: RetVal("json")
221 | })
222 | });
223 |
224 | // Helpers
225 |
226 | function dumpPool(pool) {
227 | let result = [];
228 |
229 | if (pool._actors) {
230 | pool.forEach(actor => {
231 | result.push({
232 | actorID: actor.actorID,
233 | actorPrefix: actor.actorPrefix,
234 | typeName: actor.typeName,
235 | parentID: actor._parentActor ? actor._parentActor.actorID : undefined,
236 | constructor: actor.constructor ? actor.constructor.name : undefined
237 | });
238 | });
239 | } else {
240 | // xxxHonza: there are actors (classes) stored as pools.
241 | // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=1119790#c1
242 | result = {};
243 | result.actorID = pool.actorID;
244 | result.actorPrefix = pool.actorPrefix;
245 | result.typeName = pool.typeName;
246 | result.parentID = pool.parentID;
247 | }
248 |
249 | return result;
250 | }
251 |
252 | // Exports from this module
253 | exports.InspectorActor = InspectorActor;
254 |
--------------------------------------------------------------------------------
/data/inspector/reducers/packets.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports, module) {
4 |
5 | "use strict";
6 |
7 | // RDP Window injected APIs
8 | const { Options, Locale } = require("shared/rdp-inspector-window");
9 | const { StackTrace } = require("../components/stack-frame-rep");
10 |
11 | // actions types
12 | const { types } = require("../actions/packets");
13 |
14 | /**
15 | * Initial state definition
16 | */
17 | const initialState = {
18 | paused: false,
19 | uniqueId: 0,
20 | options: {},
21 | filter: null,
22 | editedPacket: null,
23 | selectedPacket: null,
24 | removedPackets: 0,
25 | filteredPackets: [],
26 | packets: [],
27 | summary: {
28 | data: { sent: 0, received: 0},
29 | packets: { sent: 0, received: 0}
30 | },
31 | error: null,
32 | };
33 |
34 | function packetsReducer(state = initialState, action) {
35 | switch(action.type) {
36 | case types.IMPORT_PACKETS_FROMFILE:
37 | return importPacketsFromFile(state, action.data);
38 | case types.IMPORT_PACKETS_CACHE:
39 | return importPacketsCache(state, action.cache);
40 | case types.INIT_PACKETLIST_OPTIONS:
41 | return initPacketListOptions(state, action.options);
42 | case types.TOGGLE_PACKETLIST_OPTION:
43 | return togglePacketListOption(state, action.name);
44 | case types.TOGGLE_PACKETLIST_PAUSE:
45 | return togglePacketListPause(state);
46 | case types.APPEND_PACKET:
47 | return appendPacket(state, action.packetType, action.packetData);
48 | case types.APPEND_SUMMARY:
49 | return appendSummary(state, action.time);
50 | case types.APPEND_MESSAGE:
51 | return appendMessage(state, action.message, action.time);
52 | case types.SELECT_PACKET:
53 | return selectPacket(state, action.packet);
54 | case types.EDIT_PACKET:
55 | return editPacket(state, action.packet);
56 | case types.CLEAR_PACKET_LIST:
57 | return clearPacketList(state);
58 | case types.SET_PACKETLIST_ERROR:
59 | return setPacketListError(state, action.error);
60 | default:
61 | return state;
62 | }
63 | }
64 |
65 | module.exports = packetsReducer;
66 |
67 | // helpers
68 |
69 | function importPacketsFromFile(state, data) {
70 | let removedPackets = data.removedPackets || 0;
71 | let newState = clearPacketList(state);
72 |
73 | if (data.packets && data.packets.length > 0) {
74 | for (let packet of data.packets) {
75 | newState = appendToCollectedPackets(newState, packet);
76 | }
77 | }
78 |
79 | return Object.assign({}, newState, { removedPackets });
80 | }
81 |
82 | function importPacketsCache(state, cache) {
83 | let removedPackets = cache.removedPackets || 0;
84 | let newState = state;
85 |
86 | if (cache.packets && cache.packets.length > 0) {
87 | for (let packet of cache.packets) {
88 | // TODO: Trace errors
89 | newState = appendPacket(newState, packet.type, packet);
90 | }
91 | }
92 |
93 | return Object.assign({}, newState, { removedPackets });
94 | }
95 |
96 | function initPacketListOptions(state, options) {
97 | return Object.assign({}, state, {
98 | options
99 | });
100 | }
101 |
102 | function togglePacketListOption(state, name) {
103 | let options = JSON.parse(JSON.stringify(state.options));
104 | options[name] = !options[name];
105 |
106 | return Object.assign({}, state, {
107 | options
108 | });
109 | }
110 |
111 | function togglePacketListPause(state) {
112 | let paused = !state.paused;
113 | let newState;
114 |
115 | if (paused) {
116 | newState = appendMessage(state, Locale.$STR("rdpInspector.label.Paused"), new Date());
117 | } else {
118 | newState = appendMessage(state, Locale.$STR("rdpInspector.label.Unpaused"), new Date());
119 | }
120 |
121 | return Object.assign({}, newState, {
122 | paused
123 | });
124 | }
125 |
126 | function appendToCollectedPackets(state, packet) {
127 | let limit = Options.getPref("extensions.rdpinspector.packetLimit");
128 |
129 | if (state.packets.length >= limit) {
130 | state.packets.shift();
131 | }
132 |
133 | let summary = JSON.parse(JSON.stringify(state.summary));
134 |
135 | switch (packet.type) {
136 | case "send":
137 | summary.data.sent += packet.size;
138 | summary.packets.sent += 1;
139 | break;
140 | case "receive":
141 | summary.data.received += packet.size;
142 | summary.packets.received += 1;
143 | break;
144 | }
145 |
146 | packet.id = ++state.uniqueId;
147 |
148 | let packets = [ ...state.packets, packet];
149 | let filteredPackets = filterRDPInspectPackets(packets);
150 |
151 | return Object.assign({}, state, {
152 | summary, packets, filteredPackets
153 | });
154 | }
155 |
156 | function appendPacket(state, packetType, packetData) {
157 | let rawPacket = JSON.stringify(packetData.packet);
158 | let packet = {
159 | type: packetType,
160 | packet: packetData.packet,
161 | rawPacket,
162 | size: rawPacket.length,
163 | time: new Date(packetData.time),
164 | stack: new StackTrace(packetData.stack, packetType)
165 | };
166 |
167 | return appendToCollectedPackets(state, packet);
168 | }
169 |
170 | function appendSummary(state, time) {
171 | return appendToCollectedPackets(state, {
172 | type: "summary",
173 | time,
174 | data: {
175 | sent: state.summary.data.sent,
176 | received: state.summary.data.received
177 | },
178 | packets: {
179 | sent: state.summary.packets.sent,
180 | received: state.summary.packets.received
181 | }
182 | });
183 | }
184 |
185 | function appendMessage(state, message, time) {
186 | return appendToCollectedPackets(state, {
187 | type: "message", time, message
188 | });
189 | }
190 |
191 | function selectPacket(state, packet) {
192 | return Object.assign({}, state, {
193 | selectedPacket: packet
194 | });
195 | }
196 |
197 | function editPacket(state, packet) {
198 | return Object.assign({}, state, {
199 | editedPacket: packet
200 | });
201 | }
202 |
203 | function clearPacketList(state) {
204 | return Object.assign({}, state, {
205 | selectedPacket: null,
206 | packets: [],
207 | filteredPackets: [],
208 | summary: JSON.parse(JSON.stringify(initialState.summary))
209 | });
210 | }
211 |
212 | function setPacketListError(state, error) {
213 | // TODO: Trace errors
214 | return Object.assign({}, state, { error });
215 | }
216 |
217 | function filterRDPInspectPackets(packets) {
218 | var filterFrom = {};
219 |
220 | return packets.filter((packet) => {
221 | var actorId = packet.packet ? (packet.packet.to || packet.packet.from) : null;
222 |
223 | // filter our all the RDPi actorInspector actor
224 | if (actorId && actorId.indexOf("actorInspector") > 0) {
225 | return false;
226 | }
227 |
228 | if (packet.type == "send") {
229 | // filter sent RDP packets needed to register the RDPi actorInspector actor
230 | if (packet.packet.rdpInspectorInternals) {
231 | filterFrom[packet.packet.to] = filterFrom[packet.packet.to] || 0;
232 | filterFrom[packet.packet.to] += 1;
233 |
234 | return false;
235 | }
236 |
237 | // filter sent RDP packets needed to register the RDPi actorInspector actor
238 | if (packet.packet.type == "registerActor" &&
239 | packet.packet.filename.indexOf("rdpinspector-at-getfirebug-dot-com") > 0) {
240 | filterFrom[packet.packet.to] = filterFrom[packet.packet.to] || 0;
241 | filterFrom[packet.packet.to] += 1;
242 | return false;
243 | }
244 | }
245 |
246 | // filter received RDP packets needed to register the RDPi actorInspector actor
247 | if (packet.type == "receive" && filterFrom[packet.packet.from] > 0) {
248 | filterFrom[packet.packet.from] -= 1;
249 | return false;
250 | }
251 |
252 | return true;
253 | });
254 | }
255 |
256 | });
257 |
--------------------------------------------------------------------------------
/data/inspector/components/packet.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports /*, module */) {
4 |
5 | "use strict";
6 |
7 | // ReactJS
8 | const React = require("react");
9 |
10 | // Firebug SDK
11 | const { TreeView } = require("reps/tree-view");
12 |
13 | // RDP Inspector
14 | //const { TextWithTooltip } = require("./text-with-tooltip");
15 |
16 | // Constants
17 | const { div, span, ul, li, a } = React.DOM;
18 |
19 | // RDP Window injected APIs
20 | const { Locale, Str } = require("shared/rdp-inspector-window");
21 |
22 | /**
23 | * @template This template is responsible for rendering a packet.
24 | * Packets are rendered within {@link PacketList} sorted by time.
25 | *
26 | * A packet displays basic information in the list and can also
27 | * display inline preview of all inner fields.
28 | */
29 | var Packet = React.createClass({
30 | /** @lends Packet */
31 |
32 | displayName: "Packet",
33 |
34 | /**
35 | * Packet needs to be re-rendered only if the selection or
36 | * 'show inline details' option changes. This is an optimization
37 | * the makes the packet-list rendering a lot faster.
38 | */
39 | shouldComponentUpdate: function(nextProps, nextState) {
40 | var { contextMenu: prevContextMenu } = this.state || {};
41 | var { contextMenu: nextContextMenu } = nextState || {};
42 |
43 | return (this.props.selected != nextProps.selected ||
44 | this.props.showInlineDetails != nextProps.showInlineDetails ||
45 | prevContextMenu != nextContextMenu);
46 | },
47 |
48 | render: function() {
49 | var data = this.props.data;
50 | var packet = data.packet;
51 | var type = packet.type ? packet.type : "";
52 | var mode = "tiny";
53 | var classNames = ["packetPanel", data.type];
54 | var size = Str.formatSize(data.size);
55 | var time = data.time;
56 | //var stack = data.stack;
57 |
58 | // Use String.formatTime, but how to access from the content?
59 | var timeText = time.toLocaleTimeString() + "." + time.getMilliseconds();
60 | var previewData = {
61 | packet: packet
62 | };
63 |
64 | // Error packets have its own styling
65 | if (packet.error) {
66 | classNames.push("error");
67 | }
68 |
69 | // Selected packets are highlighted
70 | if (this.props.selected) {
71 | classNames.push("selected");
72 | }
73 |
74 | /*var topFrame = stack.getTopFrame();
75 | var stackFrameUrl = topFrame ? topFrame.getUrl() : null;
76 | var stackFrame = topFrame ? topFrame.getLabel() : null;*/
77 |
78 | // Inline preview component
79 | var preview = this.props.showInlineDetails ? TreeView(
80 | {data: previewData, mode: mode}) : null;
81 |
82 | if (this.props.data.type == "send") {
83 | return (
84 | div({className: classNames.join(" "), onClick: this.onClick,
85 | onContextMenu: this.onContextMenu},
86 | div({className: "packetBox"},
87 | div({className: "packetContent"},
88 | div({className: "body"},
89 | span({className: "text"},
90 | Locale.$STR("rdpInspector.label.sent") + " "
91 | ),
92 | span({className: "type"}, type),
93 | span({className: "text"},
94 | " " + Locale.$STR("rdpInspector.label.to") + " "
95 | ),
96 | span({className: "to"}, packet.to),
97 | div({},
98 | /*TextWithTooltip({
99 | tooltip: stackFrameUrl, className: "stackFrameLabel",
100 | onClick: this.onViewSource.bind(this, topFrame)},
101 | stackFrame
102 | ),*/
103 | span({className: "info"}, timeText + ", " + size)
104 | ),
105 | div({className: "preview"},
106 | preview
107 | )
108 | ),
109 | div({className: "boxArrow"})
110 | )
111 | ),
112 | this.state && this.state.contextMenu &&
113 | ul({className: "dropdown-menu", role: "menu", ref: "contextMenu",
114 | onMouseLeave: this.onContextMenuMouseLeave,
115 | style: {
116 | display: "block",
117 | top: this.state.contextMenuTop,
118 | left: this.state.contextMenuLeft
119 | }},
120 | li({role: "presentation"},
121 | a({ref: "editAndResendAction", onClick: this.onEditAndResendClick},
122 | "Edit and Resend"))
123 | )
124 | )
125 | );
126 | } else {
127 | return (
128 | div({className: classNames.join(" "), onClick: this.onClick},
129 | div({className: "packetBox"},
130 | div({className: "packetContent"},
131 | div({className: "boxArrow"}),
132 | div({className: "body"},
133 | div({className: "from"},
134 | span({className: "text"},
135 | Locale.$STR("rdpInspector.label.received") + " "
136 | ),
137 | span({}, type),
138 | span({className: "text"},
139 | " " + Locale.$STR("rdpInspector.label.from") + " "),
140 | span({}, packet.from),
141 | div({},
142 | /*TextWithTooltip({
143 | tooltip: stackFrameUrl, className: "stackFrameLabel",
144 | onClick: this.onViewSource.bind(this, topFrame)},
145 | stackFrame
146 | ),*/
147 | span({className: "info"}, timeText + ", " + size)
148 | )
149 | ),
150 | // NOTE: on issue #44, a long "consoleAPICall" received packet
151 | // was wrongly turned into a "div.errorMessage"
152 | packet.error ? div({className: "errorMessage"},
153 | div({}, packet.error),
154 | div({}, packet.message)
155 | ) : null,
156 | div({className: "preview"},
157 | preview
158 | )
159 | )
160 | )
161 | )
162 | )
163 | );
164 | }
165 | },
166 |
167 | // Event Handlers
168 | onEditAndResendClick: function() {
169 | this.setState({
170 | contextMenu: false
171 | });
172 | this.props.actions.editPacket(this.props.data.packet);
173 | },
174 |
175 | onContextMenuMouseLeave: function() {
176 | this.setState({
177 | contextMenu: false
178 | });
179 | },
180 |
181 | onContextMenu: function(event) {
182 | event.stopPropagation();
183 | event.preventDefault();
184 |
185 | this.setState({
186 | contextMenu: true,
187 | contextMenuTop: event.clientY - 16,
188 | contextMenuLeft: event.clientX - 16
189 | });
190 | this.props.actions.selectPacket(this.props.data);
191 | },
192 |
193 | onClick: function(event) {
194 | var target = event.target;
195 |
196 | event.stopPropagation();
197 | event.preventDefault();
198 |
199 | // If a 'memberLabel' is clicked inside the inline preview
200 | // tree, let's process it by the tree, so expansion and
201 | // collapsing works. Otherwise just select the packet.
202 | if (!target.classList.contains("memberLabel")) {
203 | this.props.actions.selectPacket(this.props.data);
204 | }
205 | },
206 |
207 | onViewSource: function(topFrame, event) {
208 | event.stopPropagation();
209 | event.preventDefault();
210 |
211 | this.props.actions.onViewSource({
212 | url: topFrame.url,
213 | lineNumber: topFrame.lineNumber
214 | });
215 | }
216 | });
217 |
218 | // Exports from this module
219 | exports.Packet = React.createFactory(Packet);
220 | exports.PacketComponent = Packet;
221 | });
222 |
--------------------------------------------------------------------------------
/data/shared/rdp-inspector-window.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | if (["http:", "https:", "file:"].indexOf(window.location.protocol) >= 0) {
8 | // NOTE: add RDPi injected APIs shims, to be able to run the React UI in a tab
9 | exports.Locale = window.Locale = {
10 | $STR: function(s) { return s; }
11 | };
12 |
13 | exports.Options = window.Options = {
14 | getPref: function(key) {
15 | /* eslint no-console: 0 */
16 | switch(key) {
17 | case "extensions.rdpinspector.packetLimit":
18 | return 100;
19 | default:
20 | throw Error("UNKNOWN Option.getPref: " + key);
21 | }
22 | }
23 | };
24 |
25 | exports.Str = window.Str = {
26 | formatSize: function(str) { return str; }
27 | };
28 |
29 | exports.Trace = window.Trace = {
30 | sysout: function(...args) {
31 | console.log.apply(console, args);
32 | }
33 | };
34 |
35 | exports.postChromeMessage = window.postChromeMessage = function() {
36 | console.log("POST CHROME MESSAGE", arguments);
37 | };
38 |
39 | exports.RDPConnectionList = {
40 | getConnectionsInfo: () => {},
41 | onConnectionsUpdated: {
42 | addListener: function() {},
43 | removeListener: function() {}
44 | },
45 | openRDPInspectorWindow: () => {}
46 | };
47 |
48 | // inject domTree css with a relative url (chrom urls can't be
49 | // loaded in a page not loaded from a resource or chrome urls)
50 |
51 | const domTreeStylesheet = document.createElement("link");
52 | domTreeStylesheet.setAttribute("href", "../../node_modules/firebug.sdk/skin/classic/shared/domTree.css");
53 | domTreeStylesheet.setAttribute("rel", "stylesheet");
54 |
55 | document.querySelector("head").appendChild(domTreeStylesheet);
56 | } else {
57 | /* globals Str, Locale, Options, Trace, postChromeMessage */
58 | exports.Str = Str;
59 | exports.Locale = Locale;
60 | exports.Options = Options;
61 | exports.Trace = Trace;
62 |
63 | if ("postChromeMessage" in window) {
64 | exports.postChromeMessage = window.postChromeMessage;
65 | }
66 |
67 | if ("RDPConnectionList" in window) {
68 | exports.RDPConnectionList = window.RDPConnectionList;
69 | }
70 | }
71 |
72 | function RDPInspectorView({ window, actions, store }) {
73 | this.win = window;
74 | this.actions = actions;
75 | this.store = store;
76 |
77 | // subscribe window events
78 | let subscriptions = [
79 | [ "init-options", "onInitOptions" ],
80 | [ "init-packet-list", "onInitPacketList" ],
81 | [ "send-packet", "onSendPacket" ],
82 | [ "receive-packet", "onReceivePacket" ],
83 | [ "loaded-packet-list-file", "onLoadedPacketListFile" ],
84 | [ "got-rdp-actors", "onGotRDPActors" ]
85 | ];
86 |
87 | for (let [ message, handler ] of subscriptions) {
88 | this[handler] = this[handler].bind(this);
89 | this.win.addEventListener(message, this[handler], false);
90 | }
91 | }
92 |
93 | exports.RDPInspectorView = RDPInspectorView;
94 |
95 | RDPInspectorView.prototype = {
96 | // listeners
97 | onInitOptions(event) {
98 | let options = JSON.parse(event.data);
99 | let { store, actions } = this;
100 | store.dispatch(actions.initPacketListOptions(options));
101 | },
102 |
103 | onInitPacketList(event) {
104 | let cache = JSON.parse(event.data);
105 | let { store, actions } = this;
106 | store.dispatch(actions.importPacketsCache(cache));
107 | store.dispatch(actions.appendSummary());
108 | },
109 |
110 | onSendPacket(event) {
111 | let packetData = JSON.parse(event.data);
112 | let { store, actions } = this;
113 | store.dispatch(actions.appendPacket("send", packetData));
114 | },
115 |
116 | onReceivePacket(event) {
117 | let packetData = JSON.parse(event.data);
118 | let { store, actions } = this;
119 | store.dispatch(actions.appendPacket("receive", packetData));
120 | },
121 |
122 | onGotRDPActors(event) {
123 | let actors = JSON.parse(event.data);
124 | let { store, actions } = this;
125 | store.dispatch(actions.setActors(actors));
126 | },
127 |
128 | onLoadedPacketListFile(event) {
129 | let { store, actions } = this;
130 |
131 | try {
132 | var data = deserializePacketsStore(event.data);
133 | store.dispatch(actions.importPacketsFromFile(data));
134 | } catch(e) {
135 | store.dispatch(actions.setPacketListError({
136 | message: "Error loading packets from file",
137 | details: e
138 | }));
139 | }
140 | },
141 |
142 | // app event handlers
143 |
144 | clearError() {
145 | let { store, actions } = this;
146 | store.dispatch(actions.setPacketListError(null));
147 | },
148 |
149 | selectPacket(packet) {
150 | let { store, actions } = this;
151 | store.dispatch(actions.selectPacket(packet));
152 | },
153 |
154 | editPacket(packet) {
155 | let { store, actions } = this;
156 | store.dispatch(actions.editPacket(packet));
157 | // TODO: remove this workaround
158 | window.dispatchEvent(new CustomEvent("rdpinspector:switchToPacketEditorTab"));
159 | },
160 |
161 | clear() {
162 | let { store, actions } = this;
163 | store.dispatch(actions.clearPacketList());
164 | },
165 |
166 | find() {
167 | postChromeMessage("find");
168 | },
169 |
170 | send(packet) {
171 | postChromeMessage("inject-rdp-packet", packet);
172 | },
173 |
174 | getActors() {
175 | postChromeMessage("get-rdp-actors");
176 | },
177 |
178 | appendSummary() {
179 | let { store, actions } = this;
180 | store.dispatch(actions.appendSummary());
181 |
182 | // Auto scroll to the bottom, so the new summary is
183 | // immediately visible.
184 | var node = document.querySelector(".packetsPanelBox .list");
185 | node.scrollTop = node.scrollHeight;
186 | },
187 |
188 | onShowInlineDetails() {
189 | let { store, actions } = this;
190 | store.dispatch(actions.togglePacketListOption("showInlineDetails"));
191 | postChromeMessage("options-toggle", { name: "showInlineDetails"});
192 | },
193 |
194 | onPacketCacheEnabled() {
195 | let { store, actions } = this;
196 | store.dispatch(actions.togglePacketListOption("packetCacheEnabled"));
197 | postChromeMessage("options-toggle", { name: "packetCacheEnabled"});
198 | },
199 |
200 | onPause() {
201 | let { store, actions } = this;
202 | store.dispatch(actions.togglePacketListPause());
203 | postChromeMessage("pause", store.getState().packets.paused);
204 | },
205 |
206 | loadPacketsFromFile() {
207 | postChromeMessage("load-from-file");
208 | },
209 |
210 | savePacketsToFile() {
211 | let { store, actions } = this;
212 | try {
213 | var json = serializePacketsStore(store.getState().packets);
214 | } catch(e) {
215 | store.dispatch(actions.setPacketListError({
216 | message: "Error saving packets to file",
217 | details: e
218 | }));
219 | return;
220 | }
221 |
222 | postChromeMessage("save-to-file", {
223 | data: json,
224 | contentType: "application/json",
225 | filename: "RDP-packets-dump.json"
226 | });
227 | },
228 |
229 | onViewSource(sourceLink) {
230 | postChromeMessage("view-source", sourceLink);
231 | },
232 | };
233 |
234 | // serialize / deserialze helpers
235 |
236 | const DUMP_FORMAT_VERSION = "rdp-inspector/packets-store/v1";
237 | const DUMP_FORMAT_KEYS = [
238 | "packets", "summary",
239 | "uniqueId", "removedPackets"
240 | ];
241 |
242 | function serializePacketsStore(packetsStore) {
243 | var data = {
244 | "!format!": DUMP_FORMAT_VERSION
245 | };
246 | DUMP_FORMAT_KEYS.forEach((key) => {
247 | data[key] = packetsStore[key];
248 | });
249 | return JSON.stringify(data);
250 | }
251 |
252 | function deserializePacketsStore(rawdata) {
253 | var data = JSON.parse(rawdata, (k, v) => {
254 | switch (k) {
255 | case "time":
256 | return new Date(v);
257 | default:
258 | return v;
259 | }
260 | });
261 |
262 | var res = {};
263 |
264 | if (data["!format!"] &&
265 | data["!format!"] === DUMP_FORMAT_VERSION) {
266 | DUMP_FORMAT_KEYS.forEach((key) => {
267 | res[key] = data[key];
268 | });
269 | } else {
270 | throw Error("Dump file format unrecognized");
271 | }
272 |
273 | return res;
274 | }
275 |
276 | });
277 |
--------------------------------------------------------------------------------
/data/inspector/components/actors-panel.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | define(function(require, exports/*, module*/) {
4 |
5 | "use strict";
6 |
7 | // Dependencies
8 | const React = require("react");
9 |
10 | // RDP Inspector
11 | const { ActorsToolbar } = require("./actors-toolbar");
12 |
13 | const { Locale } = require("shared/rdp-inspector-window");
14 |
15 | // Shortcuts
16 | const { tr, td, table, tbody, thead, th, div, h4 } = React.DOM;
17 |
18 | const GLOBAL_ACTORS_POOLS = "global-actors-pool";
19 | const TAB_ACTORS_POOLS = "tab-actors-pool";
20 | const ACTORS_FACTORIES = "actors-factories";
21 |
22 | var PanelTypesLabels = {};
23 | PanelTypesLabels[GLOBAL_ACTORS_POOLS] = Locale.$STR("rdpInspector.label.MainProcess");
24 | PanelTypesLabels[TAB_ACTORS_POOLS] = Locale.$STR("rdpInspector.label.ChildProcess");
25 | PanelTypesLabels[ACTORS_FACTORIES] = Locale.$STR("rdpInspector.label.ActorsFactories");
26 |
27 | /**
28 | * @template This template renders 'Actors' tab body.
29 | */
30 | var ActorsPanel = React.createClass({
31 | /** @lends ActorsPanel */
32 |
33 | displayName: "ActorsPanel",
34 |
35 | getInitialState: function() {
36 | return {
37 | panelType: GLOBAL_ACTORS_POOLS
38 | };
39 | },
40 |
41 | render: function() {
42 | var { actors } = this.props;
43 | var { panelType } = this.state;
44 |
45 | var el;
46 |
47 | switch(panelType) {
48 | case GLOBAL_ACTORS_POOLS:
49 | el = ActorsPools({
50 | data: (actors && actors.global),
51 | key: "global",
52 | searchFilter: this.props.searchFilter
53 | });
54 | break;
55 | case TAB_ACTORS_POOLS:
56 | el = ActorsPools({
57 | data: (actors && actors.tab),
58 | key: "tab",
59 | searchFilter: this.props.searchFilter
60 | });
61 | break;
62 | case ACTORS_FACTORIES:
63 | el = ActorsFactories({
64 | key: "factories",
65 | data: {
66 | global: actors && actors.global,
67 | tab: actors && actors.tab
68 | },
69 | searchFilter: this.props.searchFilter
70 | });
71 | break;
72 | }
73 |
74 | return (
75 | div({ className: "actorsPanelBox" },
76 | ActorsToolbar({ actions: this.props.actions,
77 | currentPanelType: panelType,
78 | panelTypesLabels: PanelTypesLabels,
79 | onPanelTypeSelected: this.onPanelTypeSelected
80 | }),
81 | div({ className: "actorsScrollBox" }, el)
82 | )
83 | );
84 | },
85 |
86 | onPanelTypeSelected: function(panelType) {
87 | this.setState({
88 | panelType: panelType
89 | });
90 | }
91 | });
92 |
93 | /**
94 | * @template This template renders 'ActorsPools' list in the tab content.
95 | */
96 | var ActorsPools = React.createFactory(React.createClass({
97 | /** @lends ActorsPools */
98 |
99 | displayName: "ActorsPools",
100 |
101 | render: function() {
102 | var pools = [];
103 |
104 | if (this.props.data) {
105 | var { actorPool, extraPools } = this.props.data;
106 | pools = pools.concat(actorPool, extraPools);
107 | }
108 |
109 | var poolTables = pools.map((poolData) => {
110 | var pool = poolData.pool;
111 | var poolId = poolData.id;
112 | var actorClass = false;
113 |
114 | if (!Array.isArray(pool)) {
115 | pool = [pool];
116 | actorClass = true;
117 | }
118 |
119 | if (pool.length > 0) {
120 | return PoolTable({
121 | pool: pool,
122 | actorClass: actorClass,
123 | id: poolId,
124 | key: poolId,
125 | searchFilter: this.props.searchFilter
126 | });
127 | }
128 | }).filter((el) => el);
129 |
130 | return div({ className: "poolContainer" }, poolTables);
131 | }
132 | }));
133 |
134 | /**
135 | * @template This template renders 'PoolTable' which render a table related
136 | * to a single pool of actors.
137 | */
138 | var PoolTable = React.createFactory(React.createClass({
139 | /** @lends ActorsPanel */
140 |
141 | displayName: "PoolTable",
142 |
143 | render: function() {
144 | var rows = [];
145 |
146 | // Iterate array of actors.
147 | var actors = this.props.pool;
148 | for (var i in actors) {
149 | if (this.props.searchFilter &&
150 | JSON.stringify(actors[i]).toLowerCase()
151 | .indexOf(this.props.searchFilter.toLowerCase()) < 0) {
152 | // filter out packets which don't match the filter
153 | continue;
154 | }
155 | actors[i].key = actors[i].actorID;
156 | rows.push(PoolRow(actors[i]));
157 | }
158 |
159 | // Pools are mixed with Actor objects (created using CreateClass).
160 | var className = "poolTable";
161 | if (this.props.actorClass) {
162 | className += " actorClass";
163 | }
164 |
165 | var id = this.props.id ? "ID: " + this.props.id : "";
166 |
167 | return (
168 | div({},
169 | h4({}, "Pool" + id),
170 | table({className: className},
171 | thead({className: "poolRow"},
172 | th({width: "20%"}, "Actor ID"),
173 | th({width: "20%"}, "Prefix"),
174 | th({width: "20%"}, "TypeName"),
175 | th({width: "20%"}, "Parent"),
176 | th({width: "20%"}, "Constructor")
177 | ),
178 | tbody(null, rows)
179 | )
180 | )
181 | );
182 | }
183 | }));
184 |
185 | /**
186 | * @template This template renders a single row of the 'PoolTable' .
187 | */
188 | var PoolRow = React.createFactory(React.createClass({
189 | /** @lends PoolRow */
190 |
191 | displayName: "PoolRow",
192 |
193 | render: function() {
194 | var actor = this.props;
195 | return (
196 | tr({className: "poolRow"},
197 | td({}, actor.actorID),
198 | td({}, actor.actorPrefix),
199 | td({}, actor.typeName),
200 | td({}, actor.parentID),
201 | td({}, actor.constructor)
202 | )
203 | );
204 | }
205 | }));
206 |
207 | /**
208 | * @template This template renders a single 'FactoryTable' component.
209 | */
210 | var FactoryTable = React.createFactory(React.createClass({
211 | /** @lends FactoryTable */
212 |
213 | displayName: "FactoryTable",
214 |
215 | render: function() {
216 | var rows = [];
217 |
218 | var factories = this.props.factories;
219 | for (var i in factories) {
220 | if (this.props.searchFilter &&
221 | JSON.stringify(factories[i]).toLowerCase()
222 | .indexOf(this.props.searchFilter.toLowerCase()) < 0) {
223 | // filter out packets which don't match the filter
224 | continue;
225 | }
226 |
227 | factories[i].key = factories[i].prefix + factories[i].name;
228 | rows.push(FactoryRow(factories[i]));
229 | }
230 |
231 | return (
232 | table({className: "poolTable"},
233 | thead({className: "poolRow"},
234 | th({width: "33%"}, "Name"),
235 | th({width: "33%"}, "Prefix"),
236 | th({width: "33%"}, "Constructor")
237 | ),
238 | tbody(null, rows)
239 | )
240 | );
241 | }
242 | }));
243 |
244 | /**
245 | * @template This template renders the 'ActorsFactories' list of tables.
246 | */
247 | var ActorsFactories = React.createFactory(React.createClass({
248 | /** @lends ActorsFactories */
249 |
250 | displayName: "ActorsFactories",
251 |
252 | render: function() {
253 | var main = this.props.data.global || { factories: {} };
254 | var child = this.props.data.tab || { factories: {} };
255 | var searchFilter = this.props.searchFilter;
256 |
257 | return (
258 | div({className: "poolContainer"},
259 | h4(null, "Main Process - Global Factories"),
260 | FactoryTable({ factories: main.factories.global, searchFilter: searchFilter }),
261 | h4(null, "Main Process - Tab Factories"),
262 | FactoryTable({ factories: main.factories.tab, searchFilter: searchFilter }),
263 | h4(null, "Child Process - Global Factories"),
264 | FactoryTable({ factories: child.factories.global, searchFilter: searchFilter }),
265 | h4(null, "Child Process - Tab Factories"),
266 | FactoryTable({ factories: child.factories.tab, searchFilter: searchFilter })
267 | )
268 | );
269 | }
270 | }));
271 |
272 | /**
273 | * @template This template renders a single row of the 'FactoryTable'.
274 | */
275 | var FactoryRow = React.createFactory(React.createClass({
276 | /** @lends ActorsPanel */
277 |
278 | displayName: "FactoryRow",
279 |
280 | render: function() {
281 | var factory = this.props;
282 | return (
283 | tr({className: "poolRow"},
284 | td({}, factory.name),
285 | td({}, factory.prefix),
286 | td({}, factory.ctor)
287 | )
288 | );
289 | }
290 | }));
291 |
292 | // Exports from this module
293 | exports.ActorsPanel = React.createFactory(ActorsPanel);
294 | exports.ActorsPanelComponent = ActorsPanel;
295 |
296 | });
297 |
--------------------------------------------------------------------------------
/lib/start-button.js:
--------------------------------------------------------------------------------
1 | /* See license.txt for terms of usage */
2 |
3 | "use strict";
4 |
5 | module.metadata = {
6 | "stability": "stable"
7 | };
8 |
9 | // Add-on SDK
10 | const self = require("sdk/self");
11 | const options = require("@loader/options");
12 | const { prefs } = require("sdk/simple-prefs");
13 | const { Cu } = require("chrome");
14 | const { getMostRecentBrowserWindow } = require("sdk/window/utils");
15 | const { defer } = require("sdk/core/promise");
16 | const { openTab } = require("sdk/tabs/utils");
17 | const { getNodeView } = require("sdk/view/core");
18 | const { Class } = require("sdk/core/heritage");
19 |
20 | // Firebug.SDK
21 | const { Trace/*, TraceError*/ } = require("firebug.sdk/lib/core/trace.js").get(module.id);
22 | const { Locale } = require("firebug.sdk/lib/core/locale.js");
23 | const { ToolbarButton } = require("firebug.sdk/lib/toolbar-button.js");
24 | const { Dispatcher } = require("firebug.sdk/lib/dispatcher.js");
25 |
26 | // Platform
27 | const { CustomizableUI } = Cu.import("resource:///modules/CustomizableUI.jsm", {});
28 | const { AREA_PANEL, AREA_NAVBAR } = CustomizableUI;
29 | const { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {});
30 |
31 | // DevTools
32 | // See also: https://bugzilla.mozilla.org/show_bug.cgi?id=912121
33 | const { devtools, gDevTools } = require("firebug.sdk/lib/core/devtools.js");
34 |
35 | // RDP Inspector
36 | const { ConnectionListWindow } = require("./connection-list-window");
37 |
38 | const startButtonId = "rdp-inspector-start-button";
39 |
40 | // Helpers
41 |
42 | function showToolbox(toolId) {
43 | let browser = getMostRecentBrowserWindow();
44 | let tab = browser.gBrowser.mCurrentTab;
45 | let target = devtools.TargetFactory.forTab(tab);
46 | return gDevTools.showToolbox(target, toolId);
47 | }
48 |
49 | function getToolboxWhenReady(toolId) {
50 | let deferred = defer();
51 | showToolbox(toolId).then(toolbox => {
52 | return deferred.resolve(toolbox);
53 | });
54 | return deferred.promise;
55 | }
56 |
57 | function cancelEvent(event) {
58 | event.stopPropagation();
59 | event.preventDefault();
60 | }
61 |
62 | /**
63 | * This object represents a wrapper for start button node that is
64 | * used as an anchor for Notification Panel object (displayed when
65 | * the extension is installed for the first time).
66 | *
67 | * Note that passing directly a DOM node to Panel.show() method is
68 | * an unsupported feature that will be soon replaced.
69 | * See: https://bugzilla.mozilla.org/show_bug.cgi?id=878877
70 | */
71 | var StartButtonAnchor = Class(
72 | /** @lends StartButtonAnchor */
73 | {
74 | initialize: function(button) {
75 | this.node = button;
76 | }
77 | });
78 |
79 | // getNodeView is used by the SDK panel to get the target anchor node.
80 | getNodeView.define(StartButtonAnchor, anchor => {
81 | return anchor.node;
82 | });
83 |
84 | /**
85 | * This object represents a button that is automatically displayed
86 | * in the main Firefox toolbar after the extension is installed.
87 | * It serves as the entry point to the rest of the UI.
88 | */
89 | var StartButton =
90 | /** @lends StartButton */
91 | {
92 | // Initialization
93 |
94 | initialize: function() {
95 | // Create customizable button in browser toolbar.
96 | // Read more:
97 | // https://developer.mozilla.org/en-US/docs/Mozilla/JavaScript_code_modules/CustomizableUI.jsm
98 | // https://blog.mozilla.org/addons/2014/03/06/australis-for-add-on-developers-2/
99 | CustomizableUI.createWidget({
100 | id: startButtonId,
101 | type: "custom",
102 | defaultArea: AREA_NAVBAR,
103 | allowedAreas: [AREA_PANEL, AREA_NAVBAR],
104 | onBuild: this.onBuild.bind(this)
105 | });
106 |
107 | this.connectionListWindow = new ConnectionListWindow();
108 | },
109 |
110 | shutdown: function(/*reason*/) {
111 | CustomizableUI.destroyWidget(startButtonId);
112 | },
113 |
114 | onBuild: function(doc) {
115 | Trace.sysout("startButton.onBuild;", doc);
116 |
117 | // Create a toolbar button with associated context menu.
118 | let button = new ToolbarButton({
119 | document: doc,
120 | id: startButtonId,
121 | label: "rdpInspector.startButton.title",
122 | tooltiptext: "rdpInspector.startButton.tip",
123 | type: "menu-button",
124 | "class": "toolbarbutton-1 chromeclass-toolbar-additional",
125 | image: "chrome://rdpinspector/skin/icon16.png",
126 | items: this.getMenuItems.bind(this, doc.defaultView),
127 | command: this.onToggleRdpInspector.bind(this)
128 | });
129 |
130 | return button.button;
131 | },
132 |
133 | getAnchor: function(doc) {
134 | let startButton = this.getButton(doc);
135 | return new StartButtonAnchor(startButton);
136 | },
137 |
138 | getButton: function(doc) {
139 | return doc.getElementById(startButtonId);
140 | },
141 |
142 | // Menu Actions
143 |
144 | getMenuItems: function(/*win*/) {
145 | let items = [];
146 |
147 | items.push({
148 | nol10n: true,
149 | label: Locale.$STR("rdpInspector.menu.options.label"),
150 | type: "menu",
151 | items: [
152 | {
153 | nol10n: true,
154 | label: Locale.$STR("rdpInspector.menu.autoOpenOnWebIDEConnection.label"),
155 | tooltiptext: Locale.$STR("rdpInspector.menu.autoOpenOnWebIDEConnection.tip"),
156 | type: "checkbox",
157 | checked: prefs.webideConnectionsMonitor,
158 | command: this.onToggleAutoOpenOnWebideConnections.bind(this)
159 | },
160 | {
161 | nol10n: true,
162 | label: Locale.$STR("rdpInspector.menu.packetCache.label"),
163 | tooltiptext: Locale.$STR("rdpInspector.menu.packetCache.tip"),
164 | type: "checkbox",
165 | checked: prefs.packetCacheEnabled,
166 | command: this.onTogglePacketCache.bind(this)
167 | },
168 | {
169 | nol10n: true,
170 | label: Locale.$STR("rdpInspector.menu.showInlineDetails.label"),
171 | tooltiptext: Locale.$STR("rdpInspector.menu.showInlineDetails.tip"),
172 | type: "checkbox",
173 | checked: prefs.showInlineDetails,
174 | command: this.onToggleInlineDetails.bind(this)
175 | }
176 | ]
177 | });
178 |
179 | items.push("-");
180 |
181 | items.push({
182 | nol10n: true,
183 | label: Locale.$STR("rdpInspector.menu.connectionList.label"),
184 | tooltiptext: Locale.$STR("rdpInspector.menu.connectionList.tip"),
185 | command: this.onConnectionList.bind(this)
186 | });
187 |
188 | items.push("-");
189 |
190 | items.push({
191 | nol10n: true,
192 | label: Locale.$STR("rdpInspector.menu.visitHomePage.label"),
193 | tooltiptext: Locale.$STR("rdpInspector.menu.visitHomePage.tip"),
194 | command: this.onVisitHomePage.bind(this)
195 | });
196 |
197 | items.push({
198 | nol10n: true,
199 | label: Locale.$STR("rdpInspector.menu.reportIssue.label"),
200 | tooltiptext: Locale.$STR("rdpInspector.menu.reportIssue.tip"),
201 | command: this.onReportIssue.bind(this)
202 | });
203 |
204 | items.push({
205 | nol10n: true,
206 | label: Locale.$STR("rdpInspector.menu.group.label"),
207 | tooltiptext: Locale.$STR("rdpInspector.menu.group.tip"),
208 | command: this.onDiscussionGroup.bind(this)
209 | });
210 |
211 | items.push("-");
212 |
213 | items.push({
214 | nol10n: true,
215 | label: Locale.$STR("rdpInspector.menu.about.label") + " " + self.version,
216 | tooltiptext: Locale.$STR("rdpInspector.menu.about.tip"),
217 | image: "chrome://rdpinspector/skin/logo_16x16.png",
218 | command: this.onAbout.bind(this)
219 | });
220 |
221 | return items;
222 | },
223 |
224 | onToggleRdpInspector: function() {
225 | Trace.sysout("startButton.onToggleRdpInspector;");
226 |
227 | return getToolboxWhenReady().then(toolbox => {
228 | Dispatcher.emit("onToggleRDPInspector", [{ toolbox }]);
229 |
230 | return toolbox;
231 | });
232 | },
233 |
234 | // Commands
235 | onConnectionList: function(event) {
236 | cancelEvent(event);
237 |
238 | this.connectionListWindow.open();
239 | },
240 |
241 | onToggleAutoOpenOnWebideConnections: function(event) {
242 | cancelEvent(event);
243 |
244 | prefs.autoOpenOnWebIDEConnection = !prefs.autoOpenOnWebIDEConnection;
245 | },
246 |
247 | onTogglePacketCache: function(event) {
248 | cancelEvent(event);
249 |
250 | prefs.packetCacheEnabled = !prefs.packetCacheEnabled;
251 | },
252 |
253 | onToggleInlineDetails: function(event) {
254 | cancelEvent(event);
255 |
256 | prefs.showInlineDetails = !prefs.showInlineDetails;
257 | },
258 |
259 | onAbout: function(event) {
260 | cancelEvent(event);
261 |
262 | AddonManager.getAddonByID(self.id, function (addon) {
263 | let browser = getMostRecentBrowserWindow();
264 | browser.openDialog("chrome://mozapps/content/extensions/about.xul", "",
265 | "chrome,centerscreen,modal", addon);
266 | });
267 | },
268 |
269 | onVisitHomePage: function(event) {
270 | cancelEvent(event);
271 |
272 | let browser = getMostRecentBrowserWindow();
273 | openTab(browser, options.manifest.homepage);
274 | },
275 |
276 | onReportIssue: function(event) {
277 | cancelEvent(event);
278 |
279 | let browser = getMostRecentBrowserWindow();
280 | openTab(browser, options.manifest.bugs.url);
281 | },
282 |
283 | onDiscussionGroup: function(event) {
284 | cancelEvent(event);
285 |
286 | let browser = getMostRecentBrowserWindow();
287 | openTab(browser, options.manifest.forum);
288 | }
289 | };
290 |
291 | // Registration
292 | Dispatcher.register(StartButton);
293 |
294 | // Exports from this module
295 | exports.StartButton = StartButton;
296 |
--------------------------------------------------------------------------------