Skip to content

Commit

Permalink
Merge branch 'devel' of github.com:rubrikinc/api-capture-chrome-exten…
Browse files Browse the repository at this point in the history
…sion into devel
  • Loading branch information
drew-russell committed Jun 16, 2020
2 parents d83afc7 + 98919fc commit c92edcf
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 296 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2020 Rubrik, Inc

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
9 changes: 1 addition & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Rubrik API Capture Extension
# Rubrik API Capture Extension

At the heart of the Rubrik API-first architecture is the fact that every action in the Rubrik UI has a corresponding API that is documented and available for use. Or in other words, if you can do it through the Rubrik UI, you can programmatically do the same through an API. While each of those APIs are fully documented, it can still be cumbersome to search through the API documentation to find the APIs you need and then determine which information you need to send with those API calls. This is where the API Code Capture extension comes into play.

Expand All @@ -8,12 +8,6 @@ The extension captures the API calls that both Rubrik CDM and Polaris UIs issue

![Response Body](https://user-images.githubusercontent.com/8610203/84167807-4aec9600-aa3c-11ea-80ec-1fec4b0e0c15.png)

# :hammer: Installation

The extension can be installed through the [Chrome Web Store](https://chrome.google.com/webstore/detail/rubrik-api-code-capture/mobibinbefmieblpnhabghboblgamkbj)

![Chrome Web Store](https://user-images.githubusercontent.com/8610203/84167850-58a21b80-aa3c-11ea-9d07-c9bc93069a1b.png)

# :blue_book: Documentation

After installation, you can view the extension by accessing the Chrome DevTools. There are several ways of [doing this](https://developers.google.com/web/tools/chrome-devtools/open) -- the simplest of which is to right-click anywhere on the screen and then select Inspect. Once in the DevTools, you will then need to select the Rubrik tab.
Expand All @@ -22,7 +16,6 @@ After installation, you can view the extension by accessing the Chrome DevTools.

We glady welcome contributions from the community. From updating the documentation to adding more functions for Python, all ideas are welcome. Thank you in advance for all of your issues, pull requests, and comments! :star:

- [Contributing Guide](CONTRIBUTING.md)
- [Code of Conduct](CODE_OF_CONDUCT.md)

# :pushpin: License
Expand Down
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "api-capture-chrome-extension",
"name": "api-code-capture-chrome-extension",
"version": "1.0.0",
"private": true,
"dependencies": {
Expand Down
9 changes: 4 additions & 5 deletions public/manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "Rubrik API Capture",
"short_name": "Rubrik API Capture",
"description": "Allows you to complete a workflow in the Rubrik UI and output the exact APIs, along with their response and request bodies, used to complete that workflow.",
"name": "Rubrik API Code Capture",
"short_name": "API Code Capture",
"description": "Complete a workflow in the Rubrik UI and output the exact APIs used to complete that workflow.",
"author": "Drew Russell <@drusse11>",
"version": "1.0.0",
"manifest_version": 2,
Expand All @@ -11,6 +11,5 @@
"16": "favicon.ico",
"48": "logo192.png",
"128": "logo512.png"
},
"permissions": ["tabs", "http://*/*", "https://*/*"]
}
}
40 changes: 28 additions & 12 deletions src/components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import CircularProgress from "@material-ui/core/CircularProgress";
import "./App.css";
import "./CreateApiEntry.css";

// Known API calls that the Rubrik UI uses for internal functionality checks
// Known CDM API calls that the Rubrik UI uses for internal functionality checks
const cdmBackgroundApiCalls = [
"/internal/cluster/me/is_registered",
"/internal/cluster/me/is_azure_cloud_only",
Expand Down Expand Up @@ -39,13 +39,15 @@ const cdmBackgroundApiCalls = [
"/v1/saml/sso_status",
];

// Known Polaris API calls that the Rubrik UI uses for internal functionality checks
const polarisBackgroundApiCalls = [
"FeatureFlagQuery",
"CurrentUserRolesQuery",
"CurrentUserPermissionsQuery",
"UserInfoQuery",
];

// Create a combined list of known CDM and Polaris API calls
const combinedBackgroundApiCalls = [
...cdmBackgroundApiCalls,
...polarisBackgroundApiCalls,
Expand Down Expand Up @@ -73,8 +75,11 @@ export default class App extends React.Component {
this.componentDidMount = this.componentDidMount.bind(this);
}

// Reference used for automatic scroll
scrollToBottomRef = React.createRef();

// Determine if the API is a background API and should be filtered from
// the entries created
shouldBeFilterd = (path) => {
let shouldBeFiltered = false;
if (combinedBackgroundApiCalls.includes(path)) {
Expand All @@ -86,7 +91,9 @@ export default class App extends React.Component {
// - /internal/user/{userID}
// - /internal/authorization/effective/roles?principal={userID}&resource_types=Global
// - /internal/organization/{orgID}

//
// Since the full path will vary depending on the customer, we have to use
// more generic checks.
if (
path.includes("User:::") ||
path.includes("User%3A") ||
Expand Down Expand Up @@ -131,7 +138,7 @@ export default class App extends React.Component {
continue;
}
}

// Remove "/api" from the provided path
path = request.request.url.split("/api")[1];

// Additional Polaris specifc filter for items that get past the initial
Expand All @@ -144,8 +151,7 @@ export default class App extends React.Component {
isRubrikApiCall = false;
}

// Add another layer of more generic checks for endpoints that have may
// cluster specific variables included
// Process the request body of of the API call
if (request.request.bodySize !== 0) {
let requestBodyJSON = JSON.parse(request.request.postData.text);
requestBody = JSON.stringify(requestBodyJSON, null, 2);
Expand All @@ -161,16 +167,19 @@ export default class App extends React.Component {
? (httpMethod = "mutation")
: (httpMethod = "query");
}

// Convert the request data to a GraphQL AST document for easier
// processing
let ast = parse(JSON.parse(request.request.postData.text)["query"]);
try {
path = ast["definitions"][0]["name"]["value"];
} catch (error) {}

try {
// pretty print the AST document
requestBody = print(ast);
} catch (error) {}

// Store the GraphQL request variables
try {
requestVariables = JSON.parse(request.request.postData.text)[
"variables"
Expand Down Expand Up @@ -211,26 +220,32 @@ export default class App extends React.Component {
}
};

// Used by the Pause Scroll button to set the enableScrollToBottom state
handlePauseScroll = () => {
this.state.enableScrollToBottom
? this.setState({ enableScrollToBottom: false })
: this.setState({ enableScrollToBottom: true });
};

// Contains the code used to automatically scroll to the bottom of the
// API entry list after each new entry is added
scrollToBottom = () => {
if (this.state.enableScrollToBottom) {
this.scrollToBottomRef.current.scrollIntoView({ behavior: "smooth" });
}
};

// On mount, start monitoring and processing API calls
componentDidMount() {
this.props.networkRequest.addListener(this.handleNetworkRequest);
}

// Kick off the scroll process after each entry is added
componentDidUpdate() {
this.scrollToBottom();
}

// Open the dialog used to show the Request Body/Variables and Response call
handleShowRequestBody(
id,
responseBody,
Expand All @@ -252,12 +267,14 @@ export default class App extends React.Component {
});
}

// Close the dialog used to show the Request Body/Variables and Response call
handleCloseRequestBody() {
this.setState({
showRequestBody: false,
});
}

// Handle the Recording button functionality
handleRecording = (action) => {
if (action === "start") {
this.setState({
Expand All @@ -274,10 +291,6 @@ export default class App extends React.Component {
}
};

static propTypes = {
networkRequest: React.PropTypes.object.isRequired,
};

render() {
return (
<>
Expand All @@ -287,6 +300,9 @@ export default class App extends React.Component {
handlePauseScroll={this.handlePauseScroll}
handleRecording={this.handleRecording}
/>
{/* If not Rubrik API calls are detected show the circular progress animation */}
{/* If Rubrik API calls have been detected show the top labels for each API entry */}

{this.state.apiCalls.length === 0 ? (
<>
<div className="circular-progress">
Expand All @@ -304,7 +320,7 @@ export default class App extends React.Component {
<div className="responseTime">Response Time&emsp;</div>
</div>
)}

{/* Open the dialog for the Request Body/Variables and Reponse Body */}
{this.state.showRequestBody ? (
<ApiDetailsDialog
responseBody={this.state.apiDialogContent["responseBody"]}
Expand All @@ -315,7 +331,7 @@ export default class App extends React.Component {
path={this.state.apiDialogContent["path"]}
/>
) : null}

{/* Create an entry for every Rubrik API call logged */}
<div className="panel-padding">
{this.state.apiCalls.map((apiCall) => {
return (
Expand Down
Loading

0 comments on commit c92edcf

Please sign in to comment.