Compare commits

..

36 Commits

Author SHA1 Message Date
Miroslav Bajtoš 7bcdfa7350
6.5.1
* Update LTS status in README (Miroslav Bajtoš)
 * Cursor is made pointer of the add token button (Siraj Alam)
2020-03-06 09:42:24 +01:00
Miroslav Bajtoš 53b4808d33
Merge pull request #271 from strongloop/feat/maintenance-lts
Update LTS status in README
2020-03-06 09:41:58 +01:00
Miroslav Bajtoš 6ba2ba5dc6
Update LTS status in README 2020-03-05 13:24:09 +01:00
Miroslav Bajtoš a18a6f57a1
Merge pull request #270 from sirajalam049/ui-fixes
Use "cursor: pointer" for the "Add token" button
2020-02-03 16:55:35 +01:00
Siraj Alam a2a357b968 Cursor is made pointer of the add token button 2020-01-31 00:07:04 +05:30
Miroslav Bajtoš 4149f0e7a3
6.5.0
* docs: describe GitHub advisory CVE-2019-17495 (Miroslav Bajtoš)
 * chore: improve README formatting (Miroslav Bajtoš)
 * Update README on swagger-ui (Diana Lau)
 * chore: improve issue and PR templates (Nora)
 * chore: add Node.js 12 to travis ci (Nora)
 * chore: drop support for Node.js 6 (Nora)
 * update LTS (Diana Lau)
2019-11-28 16:45:35 +01:00
Miroslav Bajtoš f4faf35575
Merge pull request #269 from strongloop/docs/sec-vuln-CVE-2019-17495
Describe GitHub advisory CVE-2019-17495
2019-11-28 15:53:24 +01:00
Miroslav Bajtoš 3098ea147f
docs: describe GitHub advisory CVE-2019-17495
Explain why this vulnerability is not affecting LoopBack users.

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-11-28 10:43:34 +01:00
Miroslav Bajtoš bc9c69a9fe
chore: improve README formatting
- Break long lines, make them fit into 80 chars
- Add section headings for individual security advisories

Signed-off-by: Miroslav Bajtoš <mbajtoss@gmail.com>
2019-11-28 10:43:34 +01:00
Diana Lau 8427632f35
Merge pull request #266 from strongloop/readme
Update README on swagger-ui
2019-11-21 11:37:20 -05:00
Diana Lau 797bbb9518 Update README on swagger-ui 2019-11-21 11:26:42 -05:00
Nora 4c357492be
Merge pull request #267 from strongloop/chore/improve-issue-templates
chore: improve issue and PR templates
2019-11-19 11:26:48 -05:00
Nora 5a90fbe6c5 chore: improve issue and PR templates 2019-11-18 23:40:05 -05:00
Nora 06fae69f57
Merge pull request #268 from strongloop/drop-node-6
Drop Node.js 6 and add Node.js 12 to Travis CI
2019-11-18 23:38:33 -05:00
Nora 2836377c49 chore: add Node.js 12 to travis ci 2019-11-15 20:48:08 -05:00
Nora 0edafc393c chore: drop support for Node.js 6 2019-11-15 20:47:57 -05:00
Diana Lau 0da66a7e09
Merge pull request #262 from strongloop/readme
update LTS
2019-06-24 09:17:48 -04:00
Diana Lau 93b2c69128 update LTS 2019-06-21 21:13:05 -04:00
Diana Lau c3e503c52c 6.4.0
* chore: update copyrights years (Agnes Lin)
 * update README for LTS status (Diana Lau)
 * Updated README with small code fix. (Pradeep Kumar Tippa)
 * fix: update lodash (jannyHou)
 * Prevent accidental upgrades to swagger-ui v3+ (Miroslav Bajtoš)
 * Update eslint & config to latest major versions (Miroslav Bajtoš)
 * Update eslint & config to latest (Miroslav Bajtoš)
2019-05-09 23:14:07 -04:00
Agnes Lin ae5c6be195
Merge pull request #261 from strongloop/copyrights
chore: update copyrights years
2019-05-07 10:20:45 -04:00
Agnes Lin c4f5b1458d chore: update copyrights years 2019-05-07 09:13:04 -04:00
Diana Lau 4abaa30cbf
Merge pull request #260 from strongloop/eol
update README for LTS status
2019-05-03 10:53:43 -04:00
Diana Lau 45b51a7205 update README for LTS status 2019-05-03 10:28:36 -04:00
Miroslav Bajtoš b83d0c23a6
Merge pull request #259 from pktippa/master
Updated README with small code fix.
2019-03-12 10:38:54 +01:00
Pradeep Kumar Tippa df43c009a1 Updated README with small code fix. 2019-03-12 11:25:32 +05:30
Miroslav Bajtoš 8274f2b1fa
Merge pull request #258 from strongloop/update/dependency-lodash
update lodash
2019-03-04 11:00:42 +01:00
jannyHou 72316ac551 fix: update lodash 2019-03-01 12:32:46 -05:00
Miroslav Bajtoš 79fbea19e2
Merge pull request #255 from strongloop/prevent-upgrade-to-swagger-ui-3
Prevent accidental upgrades to swagger-ui v3+
2019-02-05 10:16:18 +01:00
Miroslav Bajtoš 02cfb554ee
Prevent accidental upgrades to swagger-ui v3+ 2019-02-05 10:06:41 +01:00
Miroslav Bajtoš 34f8b79f04
Merge pull request #257 from strongloop/update-eslint-again
Update eslint & config to latest major versions
2019-02-05 10:05:37 +01:00
Miroslav Bajtoš 87dec34709
Update eslint & config to latest major versions 2019-02-05 08:57:18 +01:00
Miroslav Bajtoš 94b12fb52c
Merge pull request #256 from strongloop/update-eslint
Update eslint & config to latest
2019-02-05 08:47:24 +01:00
Miroslav Bajtoš ca4a996d87
Update eslint & config to latest 2019-02-05 08:36:04 +01:00
Miroslav Bajtoš 80e86adff3
6.3.1
* README: update LTS status (Miroslav Bajtoš)
2018-10-18 09:05:38 +02:00
Miroslav Bajtoš 246ba0b793
Merge pull request #251 from strongloop/update-lts
README: update LTS status
2018-10-18 09:04:57 +02:00
Miroslav Bajtoš ecac6b1a04
README: update LTS status 2018-10-16 13:06:11 +02:00
19 changed files with 395 additions and 164 deletions

View File

@ -0,0 +1,2 @@
public
coverage

View File

@ -1,37 +0,0 @@
<!--
Questions:
https://groups.google.com/forum/#!forum/loopbackjs
https://gitter.im/strongloop/loopback
Immediate support:
https://strongloop.com/api-connect-faqs/
https://strongloop.com/node-js/subscription-plans/
-->
# Description/Steps to reproduce
<!--
If feature: A description of the feature
If bug: Steps to reproduce
-->
# Link to reproduction sandbox
<!--
Link to an app sandbox for reproduction
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
# Expected result
<!--
Also include actual results if bug
-->
# Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->

50
.github/ISSUE_TEMPLATE/Bug_report.md vendored Normal file
View File

@ -0,0 +1,50 @@
---
name: Bug report
about: Create a report to help us improve
labels: bug
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
HELP US HELP YOU, PLEASE
- Do a quick search to avoid duplicate issues
- Provide as much information as possible (reproduction sandbox, use case for features, etc.)
- Consider using a more suitable venue for questions such as Stack Overflow, Gitter, etc.
Please fill in the *entire* template below.
-->
## Steps to reproduce
<!-- Describe how to reproduce the issue -->
## Current Behavior
<!-- Describe the observed result -->
## Expected Behavior
<!-- Describe what did you expect instead, what is the desired outcome? -->
## Link to reproduction sandbox
<!--
See https://loopback.io/doc/en/contrib/Reporting-issues.html#loopback-3x-bugs
Note: Failure to provide a sandbox application for reproduction purposes will result in the issue being closed.
-->
## Additional information
<!--
Copy+paste the output of these two commands:
node -e 'console.log(process.platform, process.arch, process.versions.node)'
npm ls --prod --depth 0 | grep loopback
-->
## Related Issues
<!-- Did you find other bugs that looked similar? -->
_See [Reporting Issues](http://loopback.io/doc/en/contrib/Reporting-issues.html) for more tips on writing good issues_

View File

@ -0,0 +1,25 @@
---
name: Feature request
about: Suggest an idea for this project
labels: feature
---
## Suggestion
<!-- A summary of what you'd like to see added or changed -->
## Use Cases
<!--
What do you want to use this for?
What shortcomings exist with current approaches?
-->
## Examples
<!-- Show how this would be used and what the behavior would be -->
## Acceptance criteria
TBD - will be filled by the team.

27
.github/ISSUE_TEMPLATE/Question.md vendored Normal file
View File

@ -0,0 +1,27 @@
---
name: Question
about: The issue tracker is not for questions. Please use Stack Overflow or other resources for help.
labels: question
---
<!-- 🚨 STOP 🚨 STOP 🚨 STOP 🚨
THE ISSUE TRACKER IS NOT FOR QUESTIONS.
DO NOT CREATE A NEW ISSUE TO ASK A QUESTION.
Please use one of the following resources for help:
**Questions**
- https://stackoverflow.com/tags/loopbackjs
- https://groups.google.com/forum/#!forum/loopbackjs
- https://gitter.im/strongloop/loopback
**Immediate support**
- https://strongloop.com/api-connect-faqs/
- https://strongloop.com/node-js/subscription-plans/
-->

11
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@ -0,0 +1,11 @@
blank_issues_enabled: false
contact_links:
- name: Report a security vulnerability
url: https://loopback.io/doc/en/contrib/Reporting-issues.html#security-issues
about: Do not report security vulnerabilities using GitHub issues. Please send an email to `reachsl@us.ibm.com` instead.
- name: Get help on StackOverflow
url: https://stackoverflow.com/tags/loopbackjs
about: Please ask and answer questions on StackOverflow.
- name: Join our mailing list
url: https://groups.google.com/forum/#!forum/loopbackjs
about: You can also post your question to our mailing list.

View File

@ -1,25 +1,18 @@
### Description
#### Related issues
<!--
Please use the following link syntaxes:
Please provide a high-level description of the changes made by your pull request.
- connect to #49 (to reference issues in the current repository)
- connect to strongloop/loopback#49 (to reference issues in another repository)
Include references to all related GitHub issues and other pull requests, for example:
Fixes #123
Implements #254
See also #23
-->
- connect to <link_to_referenced_issue>
## Checklist
### Checklist
<!--
- Please mark your choice with an "x" (i.e. [x], see
https://github.com/blog/1375-task-lists-in-gfm-issues-pulls-comments)
- PR's without test coverage will be closed.
-->
👉 [Read and sign the CLA (Contributor License Agreement)](https://cla.strongloop.com/agreements/strongloop/loopback-component-explorer) 👈
- [ ] `npm test` passes on your machine
- [ ] New tests added or existing tests modified to cover all changes
- [ ] Code conforms with the [style
guide](http://loopback.io/doc/en/contrib/style-guide.html)
- [ ] Code conforms with the [style guide](https://loopback.io/doc/en/contrib/style-guide-es6.html)
- [ ] Commit messages are following our [guidelines](https://loopback.io/doc/en/contrib/git-commit-messages.html)

View File

@ -1,6 +1,6 @@
sudo: false
language: node_js
node_js:
- "6"
- "8"
- "10"
- "12"

View File

@ -1,3 +1,53 @@
2020-03-06, Version 6.5.1
=========================
* Update LTS status in README (Miroslav Bajtoš)
* Cursor is made pointer of the add token button (Siraj Alam)
2019-11-28, Version 6.5.0
=========================
* docs: describe GitHub advisory CVE-2019-17495 (Miroslav Bajtoš)
* chore: improve README formatting (Miroslav Bajtoš)
* Update README on swagger-ui (Diana Lau)
* chore: improve issue and PR templates (Nora)
* chore: add Node.js 12 to travis ci (Nora)
* chore: drop support for Node.js 6 (Nora)
* update LTS (Diana Lau)
2019-05-09, Version 6.4.0
=========================
* chore: update copyrights years (Agnes Lin)
* update README for LTS status (Diana Lau)
* Updated README with small code fix. (Pradeep Kumar Tippa)
* fix: update lodash (jannyHou)
* Prevent accidental upgrades to swagger-ui v3+ (Miroslav Bajtoš)
* Update eslint & config to latest major versions (Miroslav Bajtoš)
* Update eslint & config to latest (Miroslav Bajtoš)
2018-10-18, Version 6.3.1
=========================
* README: update LTS status (Miroslav Bajtoš)
2018-09-14, Version 6.3.0
=========================

106
README.md
View File

@ -1,15 +1,19 @@
# loopback-component-explorer
**⚠️ LoopBack 3 is in Maintenance LTS mode, only critical bugs and critical
security fixes will be provided. (See
[Module Long Term Support Policy](#module-long-term-support-policy) below.)**
We urge all LoopBack 3 users to migrate their applications to LoopBack 4 as
soon as possible. Refer to our
[Migration Guide](https://loopback.io/doc/en/lb4/migration-overview.html)
for more information on how to upgrade.
## Overview
Browse and test your LoopBack app's APIs.
## Supported versions
Current|Long Term Support|Maintenance
:-:|:-:|:-:
6.x|5.x|4.x
Learn more about our LTS plan in [docs](http://loopback.io/doc/en/contrib/Long-term-support.html).
## Basic Usage
Below is a simple LoopBack application. The explorer is mounted at `/explorer`.
@ -36,6 +40,77 @@ console.log("Explorer mounted at localhost:" + port + "/explorer");
app.listen(port);
```
## A note on swagger-ui vulnerabilities
API Explorer for LoopBack 3 is built on top of `swagger-ui` version 2.x which
is no longer maintained. While there are known security vulnerabilities in
`swagger-ui`, we believe they don't affect LoopBack users.
We would love to upgrade our (LB3) API Explorer to v3 of swagger-ui, but
unfortunately such upgrade requires too much effort and more importantly
addition of new features to LB3 runtime, which would break our LTS guarantees.
For more details, see discussion in
[loopback-component-explorer#263](https://github.com/strongloop/loopback-component-explorer/issues/263).
### npm advisory 985
Link: https://www.npmjs.com/advisories/985
> Versions of swagger-ui prior to 3.0.13 are vulnerable to Cross-Site Scripting
> (XSS). The package fails to sanitize YAML files imported from URLs or
> copied-pasted. This may allow attackers to execute arbitrary JavaScript.
LoopBack's API Explorer does not allow clients to import swagger spec from YAML
URL/pasted-content. That means loopback-component-explorer **IS NOT AFFECTED**
by this vulnerability.
### npm advisory 975
Link: https://www.npmjs.com/advisories/975
> Versions of swagger-ui prior to 3.18.0 are vulnerable to Reverse Tabnapping.
> The package uses `target='_blank'` in anchor tags, allowing attackers to
> access `window.opener` for the original page. This is commonly used for
> phishing attacks.
This vulnerability affects anchor tags created from metadata provided by the
Swagger spec, for example `info.termsOfServiceUrl`. LoopBack's API Explorer
does not allow clients to provide custom swagger spec, URLs like
`info.termsOfServiceUrl` are fully in control of the LoopBack application
developer. That means loopback-component-explorer **IS NOT AFFECTED** by this
vulnerability.
### npm advisory 976
Link: https://www.npmjs.com/advisories/976
> Versions of swagger-ui prior to 3.20.9 are vulnerable to Cross-Site Scripting
> (XSS). The package fails to sanitize URLs used in the OAuth auth flow, which
> may allow attackers to execute arbitrary JavaScript.
LoopBack 3 API Explorer does not support OAuth auth flow, that means
loopback-component-explorer **IS NOT AFFECTED** by this vulnerability.
### GitHub advisory CVE-2019-17495
Link: https://github.com/advisories/GHSA-c427-hjc3-wrfw
> A Cascading Style Sheets (CSS) injection vulnerability in Swagger UI before
> 3.23.11 allows attackers to use the Relative Path Overwrite (RPO) technique
> to perform CSS-based input field value exfiltration, such as exfiltration of
> a CSRF token value.
Quoting from the
[disclosure](https://github.com/tarantula-team/CSS-injection-in-Swagger-UI/tree/15edeaaa5806aa8e83ee55d883f956a3c3573ac9):
> Weve observed that the `?url=` parameter in SwaggerUI allows an attacker to
> override an otherwise hard-coded schema file. We realize that Swagger UI
> allows users to embed untrusted Json format from remote servers This means we
> can inject json content via the GET parameter to victim Swagger UI. etc.
LoopBack 3 API Explorer does not suport `?url=` parameter, it always loads the
Swagger spec file from the LoopBack server serving the Explorer UI. That means
loopback-component-explorer **IS NOT AFFECTED** by this vulnerability.
## Upgrading from v1.x
To upgrade your application using loopback-explorer version 1.x, just replace
@ -45,7 +120,7 @@ To upgrade your application using loopback-explorer version 1.x, just replace
var explorer = require('loopback-component-explorer'); // Module was loopback-explorer in v. 2.0.1 and earlier
// v1.x - does not work anymore
app.use('/explorer', explorer(app, options);
app.use('/explorer', explorer(app, options));
// v2.x
app.use('/explorer', explorer.routes(app, options));
```
@ -183,3 +258,16 @@ Options are passed to `explorer(app, options)`.
> }
> }
> ```
## Module Long Term Support Policy
This module adopts the [
Module Long Term Support (LTS)](http://github.com/CloudNativeJS/ModuleLTS) policy,
with the following End Of Life (EOL) dates:
| Version | Status | Published | EOL |
| ------- | --------------- | --------- | -------- |
| 6.x | Maintenance LTS | Apr 2018 | Dec 2020 |
| 5.x | End-of-Life | Sep 2017 | Dec 2019 |
Learn more about our LTS plan in [docs](https://loopback.io/doc/en/contrib/Long-term-support.html).

View File

@ -1,26 +1,28 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-component-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var g = require('strong-globalize')();
'use strict';
var loopback = require('loopback');
var app = loopback();
var explorer = require('../');
var port = 3000;
const g = require('strong-globalize')();
var User = loopback.Model.extend('user', {
const loopback = require('loopback');
const app = loopback();
const explorer = require('../');
const port = 3000;
const User = loopback.Model.extend('user', {
username: 'string',
email: 'string',
sensitiveInternalProperty: 'string',
}, { hidden: ['sensitiveInternalProperty'] });
}, {hidden: ['sensitiveInternalProperty']});
User.attachTo(loopback.memory());
app.model(User);
var apiPath = '/api';
explorer(app, { basePath: apiPath });
const apiPath = '/api';
explorer(app, {basePath: apiPath});
app.use(apiPath, loopback.rest());
g.log('{{Explorer}} mounted at {{localhost:%s/explorer}}', port);

View File

@ -1,25 +1,27 @@
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback-component-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var g = require('strong-globalize')();
'use strict';
var loopback = require('loopback');
var app = loopback();
var explorer = require('../');
var port = 3000;
const g = require('strong-globalize')();
var Product = loopback.PersistedModel.extend('product', {
foo: { type: 'string', required: true },
const loopback = require('loopback');
const app = loopback();
const explorer = require('../');
const port = 3000;
const Product = loopback.PersistedModel.extend('product', {
foo: {type: 'string', required: true},
bar: 'string',
aNum: { type: 'number', min: 1, max: 10, required: true, default: 5 },
aNum: {type: 'number', min: 1, max: 10, required: true, default: 5},
});
Product.attachTo(loopback.memory());
app.model(Product);
var apiPath = '/api';
explorer(app, { basePath: apiPath });
const apiPath = '/api';
explorer(app, {basePath: apiPath});
app.use(apiPath, loopback.rest());
g.log('{{Explorer}} mounted at {{http://localhost:%s/explorer}}', port);

View File

@ -1,24 +1,24 @@
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback-component-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
'use strict';
var SG = require('strong-globalize');
const SG = require('strong-globalize');
SG.SetRootDir(__dirname);
var g = SG();
const g = SG();
/*!
* Adds dynamically-updated docs as /explorer
*/
var url = require('url');
var path = require('path');
var urlJoin = require('./lib/url-join');
var _defaults = require('lodash').defaults;
var createSwaggerObject = require('loopback-swagger').generateSwaggerSpec;
var SWAGGER_UI_ROOT = require('swagger-ui/index').dist;
var STATIC_ROOT = path.join(__dirname, 'public');
const url = require('url');
const path = require('path');
const urlJoin = require('./lib/url-join');
const _defaults = require('lodash').defaults;
const createSwaggerObject = require('loopback-swagger').generateSwaggerSpec;
const SWAGGER_UI_ROOT = require('swagger-ui/index').dist;
const STATIC_ROOT = path.join(__dirname, 'public');
module.exports = explorer;
explorer.routes = routes;
@ -31,7 +31,7 @@ explorer.routes = routes;
*/
function explorer(loopbackApplication, options) {
options = _defaults({}, options, { mountPath: '/explorer' });
options = _defaults({}, options, {mountPath: '/explorer'});
loopbackApplication.use(
options.mountPath,
routes(loopbackApplication, options)
@ -40,8 +40,8 @@ function explorer(loopbackApplication, options) {
}
function routes(loopbackApplication, options) {
var loopback = loopbackApplication.loopback;
var loopbackMajor =
const loopback = loopbackApplication.loopback;
const loopbackMajor =
(loopback && loopback.version && loopback.version.split('.')[0]) || 1;
if (loopbackMajor < 2) {
@ -59,7 +59,7 @@ function routes(loopbackApplication, options) {
swaggerUI: true,
});
var router = new loopback.Router();
const router = new loopback.Router();
mountSwagger(loopbackApplication, router, options);
@ -68,7 +68,7 @@ function routes(loopbackApplication, options) {
router.get('/config.json', function(req, res) {
// Get the path we're mounted at. It's best to get this from the referer
// in case we're proxied at a deep path.
var source = url.parse(req.headers.referer || '').pathname;
let source = url.parse(req.headers.referer || '').pathname;
// strip index.html if present in referer
if (source && /\/index\.html$/.test(source)) {
source = source.replace(/\/index\.html$/, '');
@ -118,7 +118,7 @@ function routes(loopbackApplication, options) {
* @param {Object} opts Options.
*/
function mountSwagger(loopbackApplication, swaggerApp, opts) {
var swaggerObject = createSwaggerObject(loopbackApplication, opts);
let swaggerObject = createSwaggerObject(loopbackApplication, opts);
// listening to modelRemoted event for updating the swaggerObject
// with the newly created model to appear in the Swagger UI.
@ -135,7 +135,7 @@ function mountSwagger(loopbackApplication, swaggerApp, opts) {
// when a remote method is disabled to hide that method in the Swagger UI.
loopbackApplication.on('remoteMethodDisabled', rebuildSwaggerObject);
var resourcePath = (opts && opts.resourcePath) || 'swagger.json';
let resourcePath = (opts && opts.resourcePath) || 'swagger.json';
if (resourcePath[0] !== '/') resourcePath = '/' + resourcePath;
swaggerApp.get(resourcePath, function sendSwaggerObject(req, res) {

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-component-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
@ -8,6 +8,6 @@
// Simple url joiner. Ensure we don't have to care about whether or not
// we are fed paths with leading/trailing slashes.
module.exports = function urlJoin() {
var args = Array.prototype.slice.call(arguments);
const args = Array.prototype.slice.call(arguments);
return args.join('/').replace(/\/+/g, '/');
};

View File

@ -1,9 +1,9 @@
{
"name": "loopback-component-explorer",
"version": "6.3.0",
"version": "6.5.1",
"description": "Browse and test your LoopBack app's APIs",
"engines": {
"node": ">=6"
"node": ">=8.9"
},
"main": "index.js",
"scripts": {
@ -20,15 +20,15 @@
"api",
"explorer"
],
"author": "Ritchie Martori",
"author": "IBM Corp.",
"readmeFilename": "README.md",
"bugs": {
"url": "https://github.com/strongloop/loopback-component-explorer/issues"
},
"devDependencies": {
"chai": "^3.2.0",
"eslint": "^2.8.0",
"eslint-config-loopback": "^2.0.0",
"eslint": "^5.13.0",
"eslint-config-loopback": "^13.0.0",
"loopback": "^3.19.0",
"mocha": "^5.2.0",
"supertest": "^3.1.0"
@ -36,7 +36,7 @@
"license": "MIT",
"dependencies": {
"debug": "^3.1.0",
"lodash": "^4.17.5",
"lodash": "^4.17.11",
"loopback-swagger": "^5.0.0",
"strong-globalize": "^4.1.1",
"swagger-ui": "^2.2.5"

View File

@ -34,6 +34,7 @@ body #header a#logo {
body #header form#api_selector .input a#explore {
background-color: #7dbd33 !important;
cursor: pointer;
}

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014,2016. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-component-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

View File

@ -1,16 +1,33 @@
// Copyright IBM Corp. 2013,2016. All Rights Reserved.
// Copyright IBM Corp. 2013,2019. All Rights Reserved.
// Node module: loopback-component-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT
var loopback = require('loopback');
var explorer = require('../');
var request = require('supertest');
var assert = require('assert');
var path = require('path');
var expect = require('chai').expect;
var urlJoin = require('../lib/url-join');
var os = require('os');
'use strict';
// NOTE(bajtos) It's important to run this check before we load the Explorer
// because require() may fail (e.g. with MODULE_NOT_FOUND error) and make
// it difficult to identify the actual problem
const uiVersion = require('../package.json').dependencies['swagger-ui'];
if (!uiVersion.startsWith('^2')) {
console.error(`
Upgrading from swagger-ui@2 to a newer major version (${uiVersion}) is difficult,
see https://github.com/strongloop/loopback-component-explorer/issues/254
If you are confident about this change and have manually verified API Explorer
functionality in the browser, including access-token based authentication,
then you can delete this check.
`);
process.exit(2);
}
const loopback = require('loopback');
const explorer = require('../');
const request = require('supertest');
const assert = require('assert');
const path = require('path');
const expect = require('chai').expect;
const urlJoin = require('../lib/url-join');
const os = require('os');
describe('explorer', function() {
describe('with default config', function() {
@ -18,7 +35,7 @@ describe('explorer', function() {
it('should register "loopback-component-explorer" to the app', function() {
expect(this.app.get('loopback-component-explorer'))
.to.have.property('mountPath', '/explorer');
.to.have.property('mountPath', '/explorer');
});
it('should redirect to /explorer/', function(done) {
@ -99,7 +116,7 @@ describe('explorer', function() {
it('should register "loopback-component-explorer" to the app', function() {
expect(this.app.get('loopback-component-explorer'))
.to.have.property('mountPath', '/swagger');
.to.have.property('mountPath', '/swagger');
});
it('should serve correct swagger-ui config', function(done) {
@ -120,9 +137,9 @@ describe('explorer', function() {
describe('with custom app.restApiRoot', function() {
it('should serve correct swagger-ui config', function(done) {
var app = loopback();
const app = loopback();
app.set('restApiRoot', '/rest-api-root');
app.set('remoting', { cors: false });
app.set('remoting', {cors: false});
configureRestApiAndExplorer(app);
request(app)
@ -142,9 +159,9 @@ describe('explorer', function() {
// SwaggerUI builds resource URL by concatenating basePath + resourcePath
// Since the resource paths are always startign with a slash,
// if the basePath ends with a slash too, an incorrect URL is produced
var app = loopback();
const app = loopback();
app.set('restApiRoot', '/apis/');
app.set('remoting', { cors: false });
app.set('remoting', {cors: false});
configureRestApiAndExplorer(app);
request(app)
@ -153,8 +170,8 @@ describe('explorer', function() {
.end(function(err, res) {
if (err) return done(err);
var baseUrl = res.body.basePath;
var apiPath = Object.keys(res.body.paths)[0];
const baseUrl = res.body.basePath;
const apiPath = Object.keys(res.body.paths)[0];
expect(baseUrl + apiPath).to.equal('/apis/products');
done();
@ -163,10 +180,10 @@ describe('explorer', function() {
});
describe('with custom front-end files', function() {
var app;
let app;
beforeEach(function setupExplorerWithUiDirs() {
app = loopback();
app.set('remoting', { cors: false });
app.set('remoting', {cors: false});
explorer(app, {
uiDirs: [path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui')],
});
@ -189,7 +206,7 @@ describe('explorer', function() {
request(app).get('/explorer/')
.expect(200)
.end(function(err, res) {
if (err) return done(er);
if (err) return done(err);
// expect the content of `dummy-swagger-ui/index.html`
expect(res.text).to.contain('custom index.html');
done();
@ -198,10 +215,10 @@ describe('explorer', function() {
});
describe('with swaggerUI option', function() {
var app;
let app;
beforeEach(function setupExplorerWithoutUI() {
app = loopback();
app.set('remoting', { cors: false });
app.set('remoting', {cors: false});
explorer(app, {
swaggerUI: false,
});
@ -234,11 +251,11 @@ describe('explorer', function() {
});
describe('explorer.routes API', function() {
var app;
let app;
beforeEach(function() {
app = loopback();
app.set('remoting', { cors: false });
var Product = loopback.PersistedModel.extend('product');
app.set('remoting', {cors: false});
const Product = loopback.PersistedModel.extend('product');
Product.attachTo(loopback.memory());
app.model(Product);
});
@ -256,10 +273,10 @@ describe('explorer', function() {
});
describe('when specifying custom static file root directories', function() {
var app;
let app;
beforeEach(function() {
app = loopback();
app.set('remoting', { cors: false });
app.set('remoting', {cors: false});
});
it('should allow `uiDirs` to be defined as an Array', function(done) {
@ -294,8 +311,8 @@ describe('explorer', function() {
});
it('updates swagger object when a new model is added', function(done) {
var app = loopback();
app.set('remoting', { cors: false });
const app = loopback();
app.set('remoting', {cors: false});
configureRestApiAndExplorer(app, '/explorer');
// Ensure the swagger object was built
@ -306,7 +323,7 @@ describe('explorer', function() {
if (err) return done(err);
// Create a new model
var Model = loopback.PersistedModel.extend('Customer');
const Model = loopback.PersistedModel.extend('Customer');
Model.attachTo(loopback.memory());
app.model(Model);
@ -317,9 +334,9 @@ describe('explorer', function() {
.end(function(err, res) {
if (err) return done(err);
var modelNames = Object.keys(res.body.definitions);
const modelNames = Object.keys(res.body.definitions);
expect(modelNames).to.contain('Customer');
var paths = Object.keys(res.body.paths);
const paths = Object.keys(res.body.paths);
expect(paths).to.have.contain('/Customers');
done();
@ -328,11 +345,11 @@ describe('explorer', function() {
});
it('updates swagger object when a model is removed', function(done) {
var app = loopback();
app.set('remoting', { cors: false });
const app = loopback();
app.set('remoting', {cors: false});
configureRestApiAndExplorer(app, '/explorer');
var Model = loopback.PersistedModel.extend('Customer');
const Model = loopback.PersistedModel.extend('Customer');
Model.attachTo(loopback.memory());
app.model(Model);
@ -352,9 +369,9 @@ describe('explorer', function() {
.end(function(err, res) {
if (err) return done(err);
var modelNames = Object.keys(res.body.definitions);
const modelNames = Object.keys(res.body.definitions);
expect(modelNames).to.not.contain('Customer');
var paths = Object.keys(res.body.paths);
const paths = Object.keys(res.body.paths);
expect(paths).to.not.contain('/Customers');
done();
@ -363,8 +380,8 @@ describe('explorer', function() {
});
it('updates swagger object when a remote method is disabled', function(done) {
var app = loopback();
app.set('remoting', { cors: false });
const app = loopback();
app.set('remoting', {cors: false});
configureRestApiAndExplorer(app, '/explorer');
// Ensure the swagger object was built
@ -375,10 +392,10 @@ describe('explorer', function() {
if (err) return done(err);
// Check the method that will be disabled
var paths = Object.keys(res.body.paths);
const paths = Object.keys(res.body.paths);
expect(paths).to.contain('/products/findOne');
var Product = app.models.Product;
const Product = app.models.Product;
Product.disableRemoteMethodByName('findOne');
// Request swagger.json again
@ -388,7 +405,7 @@ describe('explorer', function() {
.end(function(err, res) {
if (err) return done(err);
var paths = Object.keys(res.body.paths);
const paths = Object.keys(res.body.paths);
expect(paths).to.not.contain('/products/findOne');
done();
@ -397,8 +414,8 @@ describe('explorer', function() {
});
it('updates swagger object when a remote method is added', function(done) {
var app = loopback();
app.set('remoting', { cors: false });
const app = loopback();
app.set('remoting', {cors: false});
configureRestApiAndExplorer(app, '/explorer');
// Ensure the swagger object was built
@ -409,10 +426,10 @@ describe('explorer', function() {
if (err) return done(err);
// Check the method that will be disabled
var paths = Object.keys(res.body.paths);
const paths = Object.keys(res.body.paths);
expect(paths).to.contain('/products/findOne');
var Product = app.models.Product;
const Product = app.models.Product;
Product.findOne2 = function(cb) { cb(null, 1); };
Product.remoteMethod('findOne2', {});
@ -423,7 +440,7 @@ describe('explorer', function() {
.end(function(err, res) {
if (err) return done(err);
var paths = Object.keys(res.body.paths);
const paths = Object.keys(res.body.paths);
expect(paths).to.contain('/products/findOne2');
done();
@ -433,8 +450,8 @@ describe('explorer', function() {
function givenLoopBackAppWithExplorer(explorerBase) {
return function(done) {
var app = this.app = loopback();
app.set('remoting', { cors: false });
const app = this.app = loopback();
app.set('remoting', {cors: false});
configureRestApiAndExplorer(app, explorerBase);
done();
@ -442,11 +459,11 @@ describe('explorer', function() {
}
function configureRestApiAndExplorer(app, explorerBase) {
var Product = loopback.PersistedModel.extend('product');
const Product = loopback.PersistedModel.extend('product');
Product.attachTo(loopback.memory());
app.model(Product);
explorer(app, { mountPath: explorerBase });
explorer(app, {mountPath: explorerBase});
app.set('legacyExplorer', false);
app.use(app.get('restApiRoot') || '/', loopback.rest());
}

View File

@ -1,4 +1,4 @@
// Copyright IBM Corp. 2014. All Rights Reserved.
// Copyright IBM Corp. 2014,2019. All Rights Reserved.
// Node module: loopback-component-explorer
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT