This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+9
View File
@@ -0,0 +1,9 @@
# The MIT License
Copyright 2022 Harminder Virk, contributors
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.
+55
View File
@@ -0,0 +1,55 @@
<div align="center">
<img src="https://res.cloudinary.com/adonisjs/image/upload/q_100/v1558612869/adonis-readme_zscycu.jpg" width="600px">
</div>
<br />
<div align="center">
<h3>Shield Provider</h3>
<p>
A package to keep AdonisJS applications safe from common Web attacks like <strong>XSS</strong>, <strong>CSRF Protection</strong> and a lot more.
</p>
</div>
<br />
<div align="center">
[![gh-workflow-image]][gh-workflow-url] [![typescript-image]][typescript-url] [![npm-image]][npm-url] [![license-image]][license-url] [![synk-image]][synk-url]
</div>
<div align="center">
<h3>
<a href="https://adonisjs.com">
Website
</a>
<span> | </span>
<a href="https://docs.adonisjs.com/guides/security/web-security">
Guides
</a>
<span> | </span>
<a href="CONTRIBUTING.md">
Contributing
</a>
</h3>
</div>
<div align="center">
<sub>Built with ❤︎ by <a href="https://twitter.com/AmanVirk1">Harminder Virk</a>
</div>
[gh-workflow-image]: https://img.shields.io/github/workflow/status/adonisjs/shield/test?style=for-the-badge
[gh-workflow-url]: https://github.com/adonisjs/shield/actions/workflows/test.yml "Github action"
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
[typescript-url]: "typescript"
[npm-image]: https://img.shields.io/npm/v/@adonisjs/shield/latest.svg?style=for-the-badge&logo=npm
[npm-url]: https://www.npmjs.com/package/@adonisjs/shield/v/latest "npm"
[license-image]: https://img.shields.io/npm/l/@adonisjs/shield?color=blueviolet&style=for-the-badge
[license-url]: LICENSE.md "license"
[synk-image]: https://img.shields.io/snyk/vulnerabilities/github/adonisjs/shield?label=Synk%20Vulnerabilities&style=for-the-badge
[synk-url]: https://snyk.io/test/github/adonisjs/shield?targetFile=package.json "synk"
+6
View File
@@ -0,0 +1,6 @@
declare module '@ioc:Adonis/Core/Application' {
import { ShieldMiddlewareContract } from '@ioc:Adonis/Addons/Shield';
interface ContainerBindings {
'Adonis/Lucid/Shield': ShieldMiddlewareContract;
}
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+18
View File
@@ -0,0 +1,18 @@
/**
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare module '@ioc:Adonis/Core/Response' {
interface ResponseContract {
readonly nonce: string;
}
}
declare module '@ioc:Adonis/Core/Request' {
interface RequestContract {
csrfToken: string;
}
}
+8
View File
@@ -0,0 +1,8 @@
/**
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+4
View File
@@ -0,0 +1,4 @@
/// <reference path="shield.d.ts" />
/// <reference path="context.d.ts" />
/// <reference path="container.d.ts" />
/// <reference path="tests.d.ts" />
+12
View File
@@ -0,0 +1,12 @@
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/// <reference path="./shield.ts" />
/// <reference path="./context.ts" />
/// <reference path="./container.ts" />
/// <reference path="./tests.ts" />
+78
View File
@@ -0,0 +1,78 @@
/// <reference types="@adonisjs/http-server/build/adonis-typings" />
/// <reference types="@adonisjs/application/build/adonis-typings" />
declare module '@ioc:Adonis/Addons/Shield' {
import { CookieOptions } from '@ioc:Adonis/Core/Response';
import { ContentSecurityPolicyOptions } from 'helmet-csp';
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
/**
* Config for `X-Frame-Options` header
*/
export type XFrameOptions = {
enabled: boolean;
action?: 'DENY' | 'SAMEORIGIN';
} | {
enabled: boolean;
action?: 'ALLOW-FROM';
domain: string;
};
/**
* Config for X-Content-Type-Options
*/
export type ContentTypeSniffingOptions = {
enabled: boolean;
};
/**
* Config for HTTP Strict Transport Security (HSTS)
*/
export type HstsOptions = {
enabled: boolean;
maxAge?: string | number;
includeSubDomains?: boolean;
preload?: boolean;
};
/**
* Config for X-DNS-Prefetch-Control
*/
export type DnsPrefetchOptions = {
enabled: boolean;
allow?: boolean;
};
/**
* Config for working with CSP
*/
export type CspOptions = {
enabled: boolean;
} & ContentSecurityPolicyOptions;
/**
* Config for working with CSRF options
*/
export type CsrfOptions = {
enabled: boolean;
exceptRoutes?: string[] | ((ctx: HttpContextContract) => boolean);
enableXsrfCookie?: boolean;
methods?: ReadonlyArray<string>;
cookieOptions?: Partial<CookieOptions>;
};
/**
* Shield config file types
*/
export type ShieldConfig = {
xFrame: XFrameOptions;
contentTypeSniffing: ContentTypeSniffingOptions;
hsts: HstsOptions;
dnsPrefetch: DnsPrefetchOptions;
csp: CspOptions;
csrf: CsrfOptions;
};
/**
* Shape of the shield middleware class constructor
*/
export interface ShieldMiddlewareContract {
new (application: ApplicationContract): {
handle(ctx: HttpContextContract, next: () => Promise<void>): any;
};
}
const ShieldMiddleware: ShieldMiddlewareContract;
export default ShieldMiddleware;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+10
View File
@@ -0,0 +1,10 @@
import '@japa/api-client';
declare module '@japa/api-client' {
interface ApiRequest {
/**
* Send CSRF token to the server when making the
* API request.
*/
withCsrfToken(): this;
}
}
+11
View File
@@ -0,0 +1,11 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
require("@japa/api-client");
+11
View File
@@ -0,0 +1,11 @@
Congratulations! You have configured `@adonisjs/shield` package successfully. Just make sure to add the following middleware inside the `start/kernel.ts` file.
```ts
Server.middleware.register([
() => import('@ioc:Adonis/Core/BodyParser'),
() => import('@ioc:Adonis/Addons/Shield')
'...',
])
```
**The middleware must be right after the `BodyParser` middleware.**
+12
View File
@@ -0,0 +1,12 @@
/// <reference types="@adonisjs/application/build/adonis-typings" />
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
/**
* Provider to register shield middleware
*/
export default class ShieldProvider {
protected app: ApplicationContract;
constructor(app: ApplicationContract);
static needsApplication: boolean;
register(): void;
boot(): void;
}
+35
View File
@@ -0,0 +1,35 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
/**
* Provider to register shield middleware
*/
class ShieldProvider {
constructor(app) {
this.app = app;
}
register() {
this.app.container.singleton('Adonis/Addons/Shield', () => {
const { ShieldMiddleware } = require('../src/ShieldMiddleware');
return ShieldMiddleware;
});
}
boot() {
this.app.container.withBindings(['Adonis/Core/Response'], (Response) => {
require('../src/Bindings/Response').default(Response);
});
this.app.container.withBindings(['Japa/Preset/ApiRequest', 'Japa/Preset/ApiClient'], (ApiRequest, ApiClient) => {
const { defineTestsBindings } = require('../src/Bindings/Tests');
defineTestsBindings(ApiRequest, ApiClient);
});
}
}
ShieldProvider.needsApplication = true;
exports.default = ShieldProvider;
+6
View File
@@ -0,0 +1,6 @@
/// <reference types="@adonisjs/http-server/build/adonis-typings" />
import { ResponseConstructorContract } from '@ioc:Adonis/Core/Response';
/**
* Sharing CSP nonce with the response
*/
export default function responseBinding(Response: ResponseConstructorContract): void;
+20
View File
@@ -0,0 +1,20 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
const helpers_1 = require("@poppinss/utils/build/helpers");
/**
* Sharing CSP nonce with the response
*/
function responseBinding(Response) {
Response.getter('nonce', () => {
return helpers_1.string.generateRandom(16);
}, true);
}
exports.default = responseBinding;
+6
View File
@@ -0,0 +1,6 @@
/// <reference path="../../adonis-typings/index.d.ts" />
import { ContainerBindings } from '@ioc:Adonis/Core/Application';
/**
* Define test bindings
*/
export declare function defineTestsBindings(ApiRequest: ContainerBindings['Japa/Preset/ApiRequest'], ApiClient: ContainerBindings['Japa/Preset/ApiClient']): void;
+40
View File
@@ -0,0 +1,40 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineTestsBindings = void 0;
/// <reference path="../../adonis-typings/index.ts" />
const csrf_1 = __importDefault(require("csrf"));
/**
* Define test bindings
*/
function defineTestsBindings(ApiRequest, ApiClient) {
/**
* Set CSRF token during the HTTP request
*/
ApiRequest.macro('withCsrfToken', function () {
this['setCsrfToken'] = true;
return this;
});
ApiClient.setup(async (request) => {
const setCsrfToken = request['setCsrfToken'];
if (!setCsrfToken) {
return;
}
const tokens = new csrf_1.default();
const secret = await tokens.secret();
const token = tokens.create(secret);
request.session({ 'csrf-secret': secret });
request.header('x-csrf-token', token);
});
}
exports.defineTestsBindings = defineTestsBindings;
@@ -0,0 +1,7 @@
import { Exception } from '@poppinss/utils';
/**
* Invalid CSRF token
*/
export declare class InvalidCsrfTokenException extends Exception {
static invoke(): InvalidCsrfTokenException;
}
@@ -0,0 +1,21 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.InvalidCsrfTokenException = void 0;
const utils_1 = require("@poppinss/utils");
/**
* Invalid CSRF token
*/
class InvalidCsrfTokenException extends utils_1.Exception {
static invoke() {
return new this('Invalid CSRF Token', 403, 'E_BAD_CSRF_TOKEN');
}
}
exports.InvalidCsrfTokenException = InvalidCsrfTokenException;
+25
View File
@@ -0,0 +1,25 @@
/// <reference types="@adonisjs/application/build/adonis-typings" />
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
import type { ApplicationContract } from '@ioc:Adonis/Core/Application';
/**
* Shield middleware to protect web applications against common
* web attacks
*/
export declare class ShieldMiddleware {
private application;
private config;
private encryption;
/**
* Resolve view provider, when exists
*/
private view;
/**
* Actions to be performed
*/
private actions;
constructor(application: ApplicationContract);
/**
* Handle request
*/
handle(ctx: HttpContextContract, next: () => Promise<void>): Promise<void>;
}
+86
View File
@@ -0,0 +1,86 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ShieldMiddleware = void 0;
const standalone_1 = require("@adonisjs/core/build/standalone");
const shield = __importStar(require("../../standalone"));
/**
* Shield middleware to protect web applications against common
* web attacks
*/
let ShieldMiddleware = exports.ShieldMiddleware = class ShieldMiddleware {
constructor(application) {
this.application = application;
this.config = this.application.container.resolveBinding('Adonis/Core/Config').get('shield', {});
this.encryption = this.application.container.resolveBinding('Adonis/Core/Encryption');
/**
* Resolve view provider, when exists
*/
this.view = this.application.container.hasBinding('Adonis/Core/View')
? this.application.container.resolveBinding('Adonis/Core/View')
: undefined;
/**
* Actions to be performed
*/
this.actions = [
shield.csrfFactory(this.config.csrf || {}, this.encryption, this.view),
shield.cspFactory(this.config.csp || {}),
shield.dnsPrefetchFactory(this.config.dnsPrefetch || {}),
shield.frameGuardFactory(this.config.xFrame || {}),
shield.hstsFactory(this.config.hsts || {}),
shield.noSniffFactory(this.config.contentTypeSniffing || {}),
];
}
/**
* Handle request
*/
async handle(ctx, next) {
for (let action of this.actions) {
await action(ctx);
}
await next();
}
};
exports.ShieldMiddleware = ShieldMiddleware = __decorate([
(0, standalone_1.inject)(['Adonis/Core/Application']),
__metadata("design:paramtypes", [Object])
], ShieldMiddleware);
+8
View File
@@ -0,0 +1,8 @@
/// <reference path="../adonis-typings/index.d.ts" />
import { CspOptions } from '@ioc:Adonis/Addons/Shield';
import { noop } from './noop';
/**
* Factory that returns a function to set the `Content-Security-Policy` header based upon
* the user config
*/
export declare function cspFactory(options: CspOptions): typeof noop;
+72
View File
@@ -0,0 +1,72 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.cspFactory = void 0;
const helmet_csp_1 = __importDefault(require("helmet-csp"));
const noop_1 = require("./noop");
/**
* Directives to inspect for the `@nonce` keyword
*/
const nonceDirectives = ['defaultSrc', 'scriptSrc', 'styleSrc'];
/**
* Reads `nonce` from the ServerResponse and returns appropriate
* string
*/
function nonceFn(_, response) {
return `'nonce-${response['nonce']}'`;
}
/**
* Transform `@nonce` keywords for a given directive
*/
function transformNonceKeywords(directive) {
/**
* Transform array values. There should be only one `@nonce` keyword
*/
if (Array.isArray(directive)) {
const nonceIndex = directive.indexOf('@nonce');
if (nonceIndex > -1) {
directive[nonceIndex] = nonceFn;
}
}
return directive;
}
/**
* Factory that returns a function to set the `Content-Security-Policy` header based upon
* the user config
*/
function cspFactory(options) {
if (!options.enabled) {
return noop_1.noop;
}
if (options.directives) {
/**
* Transform directives that may contain the
* "@nonce" directive.
*/
nonceDirectives.forEach((directive) => {
if (options.directives[directive]) {
options.directives[directive] = transformNonceKeywords(options.directives[directive]);
}
});
}
const helmetCspMiddleware = (0, helmet_csp_1.default)(options);
return function csp({ response, view }) {
/**
* Helmet csp needs the `nonce` property on the HTTP ServerResponse
*/
response.response['nonce'] = response.nonce;
view.share({ cspNonce: response.nonce });
helmetCspMiddleware(response.request, response.response, () => { });
};
}
exports.cspFactory = cspFactory;
+71
View File
@@ -0,0 +1,71 @@
/// <reference path="../adonis-typings/index.d.ts" />
/// <reference types="@adonisjs/encryption/build/adonis-typings" />
import { ViewContract } from '@ioc:Adonis/Core/View';
import { CsrfOptions } from '@ioc:Adonis/Addons/Shield';
import { EncryptionContract } from '@ioc:Adonis/Core/Encryption';
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
/**
* A class to encapsulate the logic of verifying and generating
* CSRF tokens.
*/
export declare class Csrf {
private options;
private encryption;
private viewProvider?;
/**
* Factory for generate csrf secrets and tokens
*/
private tokens;
/**
* An array of methods on which the CSRF validation should be enforced.
*/
private whitelistedMethods;
/**
* An array of routes to be ignored from CSRF validation
*/
private routesToIgnore;
/**
* Name of the csrf section key stored inside the session store
*/
private secretSessionKey;
constructor(options: CsrfOptions, encryption: EncryptionContract, viewProvider?: ViewContract | undefined);
/**
* Find if a request should be validated or not
*/
private shouldValidateRequest;
/**
* Read csrf token from one of the following sources.
*
* - `_csrf` input
* - `x-csrf-token` header
* - Or `x-xsrf-token` header. The header value must be set by
* reading the `XSRF-TOKEN` cookie.
*/
private getCsrfTokenFromRequest;
/**
* Share csrf helper methods with the view engine.
*/
private shareCsrfViewLocals;
/**
* Generate a new csrf token using the csrf secret extracted from session.
*/
private generateCsrfToken;
/**
* Return the existing CSRF secret from the session or create a
* new one. Newly created secret is persisted to session at
* the same time
*/
private getCsrfSecret;
/**
* Handle csrf verification. First, get the secret,
* next, check if the request method should be
* verified. Next, attach the newly generated
* csrf token to the request object.
*/
handle(ctx: HttpContextContract): Promise<void>;
}
/**
* A factory function that returns a new function to enforce CSRF
* protection
*/
export declare function csrfFactory(options: CsrfOptions, encryption: EncryptionContract, viewProvider?: ViewContract): any;
+187
View File
@@ -0,0 +1,187 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.csrfFactory = exports.Csrf = void 0;
/// <reference path="../adonis-typings/index.ts" />
const csrf_1 = __importDefault(require("csrf"));
const noop_1 = require("./noop");
const InvalidCsrfTokenException_1 = require("./Exceptions/InvalidCsrfTokenException");
/**
* A class to encapsulate the logic of verifying and generating
* CSRF tokens.
*/
class Csrf {
constructor(options, encryption, viewProvider) {
this.options = options;
this.encryption = encryption;
this.viewProvider = viewProvider;
/**
* Factory for generate csrf secrets and tokens
*/
this.tokens = new csrf_1.default();
/**
* An array of methods on which the CSRF validation should be enforced.
*/
this.whitelistedMethods = (this.options.methods || []).map((method) => method.toLowerCase());
/**
* An array of routes to be ignored from CSRF validation
*/
this.routesToIgnore = this.options.exceptRoutes || [];
/**
* Name of the csrf section key stored inside the session store
*/
this.secretSessionKey = 'csrf-secret';
}
/**
* Find if a request should be validated or not
*/
shouldValidateRequest(ctx) {
/**
* Do not validate when whitelisted methods are defined and current
* method is not part of the white list
*/
if (this.whitelistedMethods.length &&
!this.whitelistedMethods.includes(ctx.request.method().toLowerCase())) {
return false;
}
/**
* Invoke callback when defined
*/
if (typeof this.routesToIgnore === 'function') {
return !this.routesToIgnore(ctx);
}
/**
* Do not validate when current request route is ignored inside `routesToIgnore`
* array
*/
if (this.routesToIgnore.includes(ctx.route.pattern)) {
return false;
}
return true;
}
/**
* Read csrf token from one of the following sources.
*
* - `_csrf` input
* - `x-csrf-token` header
* - Or `x-xsrf-token` header. The header value must be set by
* reading the `XSRF-TOKEN` cookie.
*/
getCsrfTokenFromRequest({ request, logger }) {
if (request.input('_csrf')) {
logger.trace('retrieved token from "_csrf" input');
return request.input('_csrf');
}
if (request.header('x-csrf-token')) {
logger.trace('retrieved token from "x-csrf-token" header');
return request.header('x-csrf-token');
}
/**
* Only entertain header based on cookie value, when `enableXsrfCookie`
* is enabled
*/
if (!this.options.enableXsrfCookie) {
return null;
}
const encryptedToken = request.header('x-xsrf-token');
if (typeof encryptedToken !== 'string' || !encryptedToken) {
return null;
}
logger.trace('retrieved token from "x-xsrf-token" header');
return this.encryption.decrypt(decodeURIComponent(encryptedToken).slice(2), 'XSRF-TOKEN');
}
/**
* Share csrf helper methods with the view engine.
*/
shareCsrfViewLocals(ctx) {
if (!ctx.view || !this.viewProvider) {
return;
}
ctx.view.share({
csrfToken: ctx.request.csrfToken,
csrfMeta: () => {
return this.viewProvider.GLOBALS.safe(`<meta name='csrf-token' content='${ctx.request.csrfToken}'>`);
},
csrfField: () => {
return this.viewProvider.GLOBALS.safe(`<input type='hidden' name='_csrf' value='${ctx.request.csrfToken}'>`);
},
});
}
/**
* Generate a new csrf token using the csrf secret extracted from session.
*/
generateCsrfToken(csrfSecret) {
return this.tokens.create(csrfSecret);
}
/**
* Return the existing CSRF secret from the session or create a
* new one. Newly created secret is persisted to session at
* the same time
*/
async getCsrfSecret(ctx) {
let csrfSecret = ctx.session.get(this.secretSessionKey);
if (!csrfSecret) {
csrfSecret = await this.tokens.secret();
ctx.session.put(this.secretSessionKey, csrfSecret);
}
return csrfSecret;
}
/**
* Handle csrf verification. First, get the secret,
* next, check if the request method should be
* verified. Next, attach the newly generated
* csrf token to the request object.
*/
async handle(ctx) {
const csrfSecret = await this.getCsrfSecret(ctx);
/**
* Validate current request before moving forward
*/
if (this.shouldValidateRequest(ctx)) {
const csrfToken = this.getCsrfTokenFromRequest(ctx);
if (!csrfToken || !this.tokens.verify(csrfSecret, csrfToken)) {
throw InvalidCsrfTokenException_1.InvalidCsrfTokenException.invoke();
}
}
/**
* Add csrf token on the request
*/
ctx.request.csrfToken = this.generateCsrfToken(csrfSecret);
/**
* Set it as a cookie
*/
if (this.options.enableXsrfCookie) {
const cookieOptions = Object.assign({}, this.options.cookieOptions, {
httpOnly: false,
});
ctx.response.encryptedCookie('XSRF-TOKEN', ctx.request.csrfToken, cookieOptions);
}
/**
* Share with the view engine
*/
this.shareCsrfViewLocals(ctx);
}
}
exports.Csrf = Csrf;
/**
* A factory function that returns a new function to enforce CSRF
* protection
*/
function csrfFactory(options, encryption, viewProvider) {
if (!options.enabled) {
return noop_1.noop;
}
const csrfMiddleware = new Csrf(options, encryption, viewProvider);
return csrfMiddleware.handle.bind(csrfMiddleware);
}
exports.csrfFactory = csrfFactory;
+7
View File
@@ -0,0 +1,7 @@
/// <reference path="../adonis-typings/index.d.ts" />
import { DnsPrefetchOptions } from '@ioc:Adonis/Addons/Shield';
import { noop } from './noop';
/**
* Factory that returns a function to set `X-DNS-Prefetch-Control` header.
*/
export declare function dnsPrefetchFactory(options: DnsPrefetchOptions): typeof noop;
+25
View File
@@ -0,0 +1,25 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.dnsPrefetchFactory = void 0;
const noop_1 = require("./noop");
/**
* Factory that returns a function to set `X-DNS-Prefetch-Control` header.
*/
function dnsPrefetchFactory(options) {
if (!options.enabled) {
return noop_1.noop;
}
const value = options.allow ? 'on' : 'off';
return function dnsPrefetch({ response }) {
response.header('X-DNS-Prefetch-Control', value);
};
}
exports.dnsPrefetchFactory = dnsPrefetchFactory;
+8
View File
@@ -0,0 +1,8 @@
/// <reference path="../adonis-typings/index.d.ts" />
import { XFrameOptions } from '@ioc:Adonis/Addons/Shield';
import { noop } from './noop';
/**
* Factory function that returns a function to set `X-Frame-Options` header
* based upon given user options.
*/
export declare function frameGuardFactory(options: XFrameOptions): typeof noop;
+34
View File
@@ -0,0 +1,34 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.frameGuardFactory = void 0;
const noop_1 = require("./noop");
const ALLOWED_ACTIONS = ['DENY', 'ALLOW-FROM', 'SAMEORIGIN'];
/**
* Factory function that returns a function to set `X-Frame-Options` header
* based upon given user options.
*/
function frameGuardFactory(options) {
if (!options.enabled) {
return noop_1.noop;
}
const action = (options.action || 'SAMEORIGIN').toUpperCase();
if (!ALLOWED_ACTIONS.includes(action)) {
throw new Error('frameGuard: Action must be one of "DENY", "ALLOW-FROM" or "SAMEORGIGIN"');
}
if (action === 'ALLOW-FROM' && !options['domain']) {
throw new Error('frameGuard: Domain value is required when using action as "ALLOW-FROM"');
}
const result = action === 'ALLOW-FROM' ? `${action} ${options['domain']}` : action;
return function frameGuard({ response }) {
response.header('X-Frame-Options', result);
};
}
exports.frameGuardFactory = frameGuardFactory;
+8
View File
@@ -0,0 +1,8 @@
/// <reference path="../adonis-typings/index.d.ts" />
import { HstsOptions } from '@ioc:Adonis/Addons/Shield';
import { noop } from './noop';
/**
* Factory function that returns a new function to Add `Strict-Transport-Security`
* header based upon given user options.
*/
export declare function hstsFactory(options: HstsOptions): typeof noop;
+49
View File
@@ -0,0 +1,49 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.hstsFactory = void 0;
/// <reference path="../adonis-typings/index.ts" />
const helpers_1 = require("@poppinss/utils/build/helpers");
const noop_1 = require("./noop");
const DEFAULT_MAX_AGE = 180 * 24 * 60 * 60;
/**
* Normalizes the max age to a valid number
*/
function normalizeMaxAge(maxAge) {
if (maxAge === null || maxAge === undefined) {
return DEFAULT_MAX_AGE;
}
maxAge = (typeof maxAge === 'string' ? helpers_1.string.toMs(maxAge) : maxAge);
if (maxAge < 0) {
throw new Error('Max age for "shield.hsts" cannot be a negative value');
}
return maxAge;
}
/**
* Factory function that returns a new function to Add `Strict-Transport-Security`
* header based upon given user options.
*/
function hstsFactory(options) {
if (!options.enabled) {
return noop_1.noop;
}
const maxAge = normalizeMaxAge(options.maxAge);
let value = `max-age=${maxAge}`;
if (options.includeSubDomains) {
value += '; includeSubDomains';
}
if (options.preload) {
value += '; preload';
}
return function hsts({ response }) {
response.header('Strict-Transport-Security', value);
};
}
exports.hstsFactory = hstsFactory;
+8
View File
@@ -0,0 +1,8 @@
/// <reference path="../adonis-typings/index.d.ts" />
import { ContentTypeSniffingOptions } from '@ioc:Adonis/Addons/Shield';
import { noop } from './noop';
/**
* Factory function that returns a function to Add `X-Content-Type-Options`
* header based upon given user options.
*/
export declare function noSniffFactory(options: ContentTypeSniffingOptions): typeof noop;
+25
View File
@@ -0,0 +1,25 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.noSniffFactory = void 0;
const noop_1 = require("./noop");
/**
* Factory function that returns a function to Add `X-Content-Type-Options`
* header based upon given user options.
*/
function noSniffFactory(options) {
if (!options.enabled) {
return noop_1.noop;
}
return function noSniff({ response }) {
response.header('X-Content-Type-Options', 'nosniff');
};
}
exports.noSniffFactory = noSniffFactory;
+2
View File
@@ -0,0 +1,2 @@
import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext';
export declare function noop(_: HttpContextContract): void;
+13
View File
@@ -0,0 +1,13 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.noop = void 0;
function noop(_) { }
exports.noop = noop;
+6
View File
@@ -0,0 +1,6 @@
export { cspFactory } from './src/csp';
export { csrfFactory } from './src/csrf';
export { hstsFactory } from './src/hsts';
export { noSniffFactory } from './src/noSniff';
export { frameGuardFactory } from './src/frameGuard';
export { dnsPrefetchFactory } from './src/dnsPrefetch';
+23
View File
@@ -0,0 +1,23 @@
"use strict";
/*
* @adonisjs/shield
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.dnsPrefetchFactory = exports.frameGuardFactory = exports.noSniffFactory = exports.hstsFactory = exports.csrfFactory = exports.cspFactory = void 0;
var csp_1 = require("./src/csp");
Object.defineProperty(exports, "cspFactory", { enumerable: true, get: function () { return csp_1.cspFactory; } });
var csrf_1 = require("./src/csrf");
Object.defineProperty(exports, "csrfFactory", { enumerable: true, get: function () { return csrf_1.csrfFactory; } });
var hsts_1 = require("./src/hsts");
Object.defineProperty(exports, "hstsFactory", { enumerable: true, get: function () { return hsts_1.hstsFactory; } });
var noSniff_1 = require("./src/noSniff");
Object.defineProperty(exports, "noSniffFactory", { enumerable: true, get: function () { return noSniff_1.noSniffFactory; } });
var frameGuard_1 = require("./src/frameGuard");
Object.defineProperty(exports, "frameGuardFactory", { enumerable: true, get: function () { return frameGuard_1.frameGuardFactory; } });
var dnsPrefetch_1 = require("./src/dnsPrefetch");
Object.defineProperty(exports, "dnsPrefetchFactory", { enumerable: true, get: function () { return dnsPrefetch_1.dnsPrefetchFactory; } });
+237
View File
@@ -0,0 +1,237 @@
/**
* Config source: https://git.io/Jvwvt
*
* Feel free to let us know via PR, if you find something broken in this config
* file.
*/
import { ShieldConfig } from '@ioc:Adonis/Addons/Shield'
/*
|--------------------------------------------------------------------------
| Content Security Policy
|--------------------------------------------------------------------------
|
| Content security policy filters out the origins not allowed to execute
| and load resources like scripts, styles and fonts. There are wide
| variety of options to choose from.
*/
export const csp: ShieldConfig['csp'] = {
/*
|--------------------------------------------------------------------------
| Enable/disable CSP
|--------------------------------------------------------------------------
|
| The CSP rules are disabled by default for seamless onboarding.
|
*/
enabled: false,
/*
|--------------------------------------------------------------------------
| Directives
|--------------------------------------------------------------------------
|
| All directives are defined in camelCase and here is the list of
| available directives and their possible values.
|
| https://content-security-policy.com
|
| @example
| directives: {
| defaultSrc: ["'self'", '@nonce', 'cdnjs.cloudflare.com']
| }
|
*/
directives: {
},
/*
|--------------------------------------------------------------------------
| Report only
|--------------------------------------------------------------------------
|
| Setting `reportOnly=true` will not block the scripts from running and
| instead report them to a URL.
|
*/
reportOnly: false,
}
/*
|--------------------------------------------------------------------------
| CSRF Protection
|--------------------------------------------------------------------------
|
| CSRF Protection adds another layer of security by making sure, actionable
| routes does have a valid token to execute an action.
|
*/
export const csrf: ShieldConfig['csrf'] = {
/*
|--------------------------------------------------------------------------
| Enable/Disable CSRF
|--------------------------------------------------------------------------
*/
enabled: true,
/*
|--------------------------------------------------------------------------
| Routes to Ignore
|--------------------------------------------------------------------------
|
| Define an array of route patterns that you want to ignore from CSRF
| validation. Make sure the route patterns are started with a leading
| slash. Example:
|
| `/foo/bar`
|
| Also you can define a function that is evaluated on every HTTP Request.
| ```
| exceptRoutes: ({ request }) => request.url().includes('/api')
| ```
|
*/
exceptRoutes: [],
/*
|--------------------------------------------------------------------------
| Enable Sharing Token Via Cookie
|--------------------------------------------------------------------------
|
| When the following flag is enabled, AdonisJS will drop `XSRF-TOKEN`
| cookie that frontend frameworks can read and return back as a
| `X-XSRF-TOKEN` header.
|
| The cookie has `httpOnly` flag set to false, so it is little insecure and
| can be turned off when you are not using a frontend framework making
| AJAX requests.
|
*/
enableXsrfCookie: true,
/*
|--------------------------------------------------------------------------
| Methods to Validate
|--------------------------------------------------------------------------
|
| Define an array of HTTP methods to be validated for a valid CSRF token.
|
*/
methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
}
/*
|--------------------------------------------------------------------------
| DNS Prefetching
|--------------------------------------------------------------------------
|
| DNS prefetching allows browsers to proactively perform domain name
| resolution in background.
|
| Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-DNS-Prefetch-Control
|
*/
export const dnsPrefetch: ShieldConfig['dnsPrefetch'] = {
/*
|--------------------------------------------------------------------------
| Enable/disable this feature
|--------------------------------------------------------------------------
*/
enabled: true,
/*
|--------------------------------------------------------------------------
| Allow or Dis-Allow Explicitly
|--------------------------------------------------------------------------
|
| The `enabled` boolean does not set `X-DNS-Prefetch-Control` header. However
| the `allow` boolean controls the value of `X-DNS-Prefetch-Control` header.
|
| - When `allow = true`, then `X-DNS-Prefetch-Control = 'on'`
| - When `allow = false`, then `X-DNS-Prefetch-Control = 'off'`
|
*/
allow: true,
}
/*
|--------------------------------------------------------------------------
| Iframe Options
|--------------------------------------------------------------------------
|
| xFrame defines whether or not your website can be embedded inside an
| iframe. Choose from one of the following options.
|
| - DENY
| - SAMEORIGIN
| - ALLOW-FROM http://example.com
|
| Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
*/
export const xFrame: ShieldConfig['xFrame'] = {
enabled: true,
action: 'DENY',
}
/*
|--------------------------------------------------------------------------
| Http Strict Transport Security
|--------------------------------------------------------------------------
|
| A security to ensure that a browser always makes a connection over
| HTTPS.
|
| Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security
|
*/
export const hsts: ShieldConfig['hsts'] = {
enabled: true,
/*
|--------------------------------------------------------------------------
| Max Age
|--------------------------------------------------------------------------
|
| Control, how long the browser should remember that a site is only to be
| accessed using HTTPS.
|
*/
maxAge: '180 days',
/*
|--------------------------------------------------------------------------
| Include Subdomains
|--------------------------------------------------------------------------
|
| Apply rules on the subdomains as well.
|
*/
includeSubDomains: true,
/*
|--------------------------------------------------------------------------
| Preloading
|--------------------------------------------------------------------------
|
| Google maintains a service to register your domain and it will preload
| the HSTS policy. Learn more https://hstspreload.org/
|
*/
preload: false,
}
/*
|--------------------------------------------------------------------------
| No Sniff
|--------------------------------------------------------------------------
|
| Browsers have a habit of sniffing content-type of a response. Which means
| files with .txt extension containing Javascript code will be executed as
| Javascript. You can disable this behavior by setting nosniff to false.
|
| Learn more at https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options
|
*/
export const contentTypeSniffing: ShieldConfig['contentTypeSniffing'] = {
enabled: true,
}
@@ -0,0 +1,9 @@
# The MIT License
Copyright 2021 Harminder Virk, contributors
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.
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
export * from './src/Helpers';
@@ -0,0 +1,25 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./src/Helpers"), exports);
@@ -0,0 +1,10 @@
export * as lodash from './src/lodash';
export { slash } from './src/slash';
export { flatten } from './src/flatten';
export { Exception } from './src/Exception';
export { safeParse } from './src/safeParse';
export { esmRequire } from './src/esmRequire';
export { esmResolver } from './src/esmResolver';
export { safeStringify } from './src/safeStringify';
export { defineStaticProperty } from './src/defineStaticProperty';
export { ManagerConfigValidator } from './src/ManagerConfigValidator';
@@ -0,0 +1,53 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ManagerConfigValidator = exports.defineStaticProperty = exports.safeStringify = exports.esmResolver = exports.esmRequire = exports.safeParse = exports.Exception = exports.flatten = exports.slash = exports.lodash = void 0;
exports.lodash = __importStar(require("./src/lodash"));
var slash_1 = require("./src/slash");
Object.defineProperty(exports, "slash", { enumerable: true, get: function () { return slash_1.slash; } });
var flatten_1 = require("./src/flatten");
Object.defineProperty(exports, "flatten", { enumerable: true, get: function () { return flatten_1.flatten; } });
var Exception_1 = require("./src/Exception");
Object.defineProperty(exports, "Exception", { enumerable: true, get: function () { return Exception_1.Exception; } });
var safeParse_1 = require("./src/safeParse");
Object.defineProperty(exports, "safeParse", { enumerable: true, get: function () { return safeParse_1.safeParse; } });
var esmRequire_1 = require("./src/esmRequire");
Object.defineProperty(exports, "esmRequire", { enumerable: true, get: function () { return esmRequire_1.esmRequire; } });
var esmResolver_1 = require("./src/esmResolver");
Object.defineProperty(exports, "esmResolver", { enumerable: true, get: function () { return esmResolver_1.esmResolver; } });
var safeStringify_1 = require("./src/safeStringify");
Object.defineProperty(exports, "safeStringify", { enumerable: true, get: function () { return safeStringify_1.safeStringify; } });
var defineStaticProperty_1 = require("./src/defineStaticProperty");
Object.defineProperty(exports, "defineStaticProperty", { enumerable: true, get: function () { return defineStaticProperty_1.defineStaticProperty; } });
var ManagerConfigValidator_1 = require("./src/ManagerConfigValidator");
Object.defineProperty(exports, "ManagerConfigValidator", { enumerable: true, get: function () { return ManagerConfigValidator_1.ManagerConfigValidator; } });
@@ -0,0 +1,17 @@
/**
* Extended Error object with the option to set error `status` and `code`.
* At AdonisJs, we prefer exceptions with proper error codes to handle
* them without relying on message pattern matching.
*
* ```js
* new Exception('message', 500, 'E_RUNTIME_EXCEPTION')
* ```
*/
export declare class Exception extends Error {
name: string;
message: string;
help?: string;
code?: string;
status: number;
constructor(message: string, status?: number, code?: string);
}
@@ -0,0 +1,68 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Exception = void 0;
/**
* Extended Error object with the option to set error `status` and `code`.
* At AdonisJs, we prefer exceptions with proper error codes to handle
* them without relying on message pattern matching.
*
* ```js
* new Exception('message', 500, 'E_RUNTIME_EXCEPTION')
* ```
*/
class Exception extends Error {
constructor(message, status = 500, code) {
super(message);
/**
* Set error message
*/
Object.defineProperty(this, 'message', {
configurable: true,
enumerable: false,
value: code ? `${code}: ${message}` : message,
writable: true,
});
/**
* Set error name as a public property
*/
Object.defineProperty(this, 'name', {
configurable: true,
enumerable: false,
value: this.constructor.name,
writable: true,
});
/**
* Set status as a public property
*/
Object.defineProperty(this, 'status', {
configurable: true,
enumerable: false,
value: status,
writable: true,
});
/**
* Set error code as a public property (only when defined)
*/
if (code) {
Object.defineProperty(this, 'code', {
configurable: true,
enumerable: false,
value: code,
writable: true,
});
}
/**
* Update the stack trace
*/
Error.captureStackTrace(this, this.constructor);
}
}
exports.Exception = Exception;
@@ -0,0 +1,28 @@
/**
* Message builder exposes an API to JSON.stringify values by encoding purpose
* and expiryDate inside them. It returns a readable string, which is the
* output of `JSON.stringify`.
*
* Why use this over `JSON.stringify`?
*
* - It protects you from JSON poisioning
* - Allows encoding expiry dates to the message. It means, the message builer is
* helpful, when you want to encode a message and pass it around, but also control
* the TTL of the message
* - Allows encoding purpose. Again, useful for distribution.
*/
export declare class MessageBuilder {
private getExpiryDate;
/**
* Returns a boolean telling, if message has been expired or not
*/
private isExpired;
/**
* Builds a message by encoding expiry and purpose inside it
*/
build(message: any, expiresIn?: string | number, purpose?: string): string;
/**
* Verifies the message for expiry and purpose
*/
verify<T extends any>(message: any, purpose?: string): null | T;
}
@@ -0,0 +1,97 @@
"use strict";
/*
* @adonisjs/encryption
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MessageBuilder = void 0;
const ms_1 = __importDefault(require("ms"));
const safeParse_1 = require("../safeParse");
const safeStringify_1 = require("../safeStringify");
/**
* Message builder exposes an API to JSON.stringify values by encoding purpose
* and expiryDate inside them. It returns a readable string, which is the
* output of `JSON.stringify`.
*
* Why use this over `JSON.stringify`?
*
* - It protects you from JSON poisioning
* - Allows encoding expiry dates to the message. It means, the message builer is
* helpful, when you want to encode a message and pass it around, but also control
* the TTL of the message
* - Allows encoding purpose. Again, useful for distribution.
*/
class MessageBuilder {
getExpiryDate(expiresIn) {
if (!expiresIn) {
return undefined;
}
const expiryMs = typeof expiresIn === 'string' ? (0, ms_1.default)(expiresIn) : expiresIn;
if (expiryMs === undefined || expiryMs === null) {
throw new Error(`Invalid value for expiresIn "${expiresIn}"`);
}
return new Date(Date.now() + expiryMs);
}
/**
* Returns a boolean telling, if message has been expired or not
*/
isExpired(message) {
if (!message.expiryDate) {
return false;
}
try {
const expiryDate = new Date(message.expiryDate);
return isNaN(expiryDate.getTime()) || expiryDate < new Date();
}
catch (error) {
return true;
}
}
/**
* Builds a message by encoding expiry and purpose inside it
*/
build(message, expiresIn, purpose) {
const expiryDate = this.getExpiryDate(expiresIn);
return (0, safeStringify_1.safeStringify)({ message, purpose, expiryDate });
}
/**
* Verifies the message for expiry and purpose
*/
verify(message, purpose) {
const parsed = (0, safeParse_1.safeParse)(message);
/**
* Safe parse returns the value as it is when unable to JSON.parse it. However, in
* our case if value was correctly parsed, it should never match the input
*/
if (parsed === message) {
return null;
}
/**
* Missing ".message" property
*/
if (!parsed.message) {
return null;
}
/**
* Ensure purposes are same.
*/
if (parsed.purpose !== purpose) {
return null;
}
/**
* Ensure isn't expired
*/
if (this.isExpired(parsed)) {
return null;
}
return parsed.message;
}
}
exports.MessageBuilder = MessageBuilder;
@@ -0,0 +1,46 @@
/**
* A simple class to build an object incrementally. It is helpful when you
* want to add properties to the object conditionally.
*
* Instead of writing
* ```
* const obj = {
* ...(user.id ? { id: user.id } : {}),
* ...(user.firstName && user.lastName ? { name: `${user.firstName} ${user.lastName}` } : {}),
* }
* ```
*
* You can write
*
* const obj = new ObjectBuilder()
* .add('id', user.id)
* .add(
* 'fullName',
* user.firstName && user.lastName ? `${user.firstName} ${user.lastName}` : undefined
* )
* .value
*/
export declare class ObjectBuilder {
private ignoreNull?;
value: any;
constructor(ignoreNull?: boolean | undefined);
/**
* Add value to the property.
*
* - Undefined values are ignored
* - Null values are ignored, when `ignoreNull` is set to true
*/
add(key: string, value: any): this;
/**
* Remove value from the object
*/
remove(key: string): this;
/**
* Find if a value exists
*/
has(key: string): boolean;
/**
* Get the existing value
*/
get<T extends any>(key: string): T;
}
@@ -0,0 +1,75 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ObjectBuilder = void 0;
/**
* A simple class to build an object incrementally. It is helpful when you
* want to add properties to the object conditionally.
*
* Instead of writing
* ```
* const obj = {
* ...(user.id ? { id: user.id } : {}),
* ...(user.firstName && user.lastName ? { name: `${user.firstName} ${user.lastName}` } : {}),
* }
* ```
*
* You can write
*
* const obj = new ObjectBuilder()
* .add('id', user.id)
* .add(
* 'fullName',
* user.firstName && user.lastName ? `${user.firstName} ${user.lastName}` : undefined
* )
* .value
*/
class ObjectBuilder {
constructor(ignoreNull) {
this.ignoreNull = ignoreNull;
this.value = {};
}
/**
* Add value to the property.
*
* - Undefined values are ignored
* - Null values are ignored, when `ignoreNull` is set to true
*/
add(key, value) {
if (value === undefined) {
return this;
}
if (this.ignoreNull === true && value === null) {
return this;
}
this.value[key] = value;
return this;
}
/**
* Remove value from the object
*/
remove(key) {
delete this.value[key];
return this;
}
/**
* Find if a value exists
*/
has(key) {
return this.get(key) !== undefined;
}
/**
* Get the existing value
*/
get(key) {
return this.value[key];
}
}
exports.ObjectBuilder = ObjectBuilder;
@@ -0,0 +1,33 @@
/// <reference types="node" />
/**
* Helper class to base64 encode/decode values with option
* for url encoding and decoding
*/
declare class Base64 {
/**
* Base64 encode Buffer or string
*/
encode(arrayBuffer: ArrayBuffer | SharedArrayBuffer): string;
encode(data: string, encoding?: BufferEncoding): string;
/**
* Base64 decode a previously encoded string or Buffer.
*/
decode(encode: string, encoding: BufferEncoding, strict: true): string | null;
decode(encode: string, encoding: undefined, strict: true): string | null;
decode(encode: string, encoding?: BufferEncoding, strict?: false): string;
decode(encode: Buffer, encoding?: BufferEncoding): string;
/**
* Base64 encode Buffer or string to be URL safe. (RFC 4648)
*/
urlEncode(arrayBuffer: ArrayBuffer | SharedArrayBuffer): string;
urlEncode(data: string, encoding?: BufferEncoding): string;
/**
* Base64 URL decode a previously encoded string or Buffer. (RFC 4648)
*/
urlDecode(encode: string, encoding: BufferEncoding, strict: true): string | null;
urlDecode(encode: string, encoding: undefined, strict: true): string | null;
urlDecode(encode: string, encoding?: BufferEncoding, strict?: false): string;
urlDecode(encode: Buffer, encoding?: BufferEncoding): string;
}
export declare const base64: Base64;
export {};
@@ -0,0 +1,48 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.base64 = void 0;
/**
* Helper class to base64 encode/decode values with option
* for url encoding and decoding
*/
class Base64 {
encode(data, encoding) {
if (typeof data === 'string') {
return Buffer.from(data, encoding).toString('base64');
}
return Buffer.from(data).toString('base64');
}
decode(encoded, encoding = 'utf-8', strict = false) {
if (Buffer.isBuffer(encoded)) {
return encoded.toString(encoding);
}
const decoded = Buffer.from(encoded, 'base64').toString(encoding);
if (strict && this.encode(decoded, encoding) !== encoded) {
return null;
}
return decoded;
}
urlEncode(data, encoding) {
const encoded = typeof data === 'string' ? this.encode(data, encoding) : this.encode(data);
return encoded.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
}
urlDecode(encoded, encoding = 'utf-8', strict = false) {
if (Buffer.isBuffer(encoded)) {
return encoded.toString(encoding);
}
const decoded = Buffer.from(encoded, 'base64').toString(encoding);
if (strict && this.urlEncode(decoded, encoding) !== encoded) {
return null;
}
return decoded;
}
}
exports.base64 = new Base64();
@@ -0,0 +1,21 @@
declare type Constructor = new (...args: any[]) => any;
/**
* Converting unions to intersection
*/
declare type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never;
/**
* Normalizes constructor to work with mixins. There is an open bug for mixins
* to allow constructors other than `...args: any[]`
*
* https://github.com/microsoft/TypeScript/issues/37142
*/
export declare type NormalizeConstructor<T extends Constructor> = {
new (...args: any[]): InstanceType<T>;
} & Omit<T, 'constructor'>;
/**
* Compose a class by applying mixins to it.
* The code is inspired by https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/, its
* just that I have added the support for static types too.
*/
export declare const compose: <SuperClass extends Constructor, M extends ((superclass: SuperClass) => Constructor)[]>(superclass: SuperClass, ...mixins: M) => SuperClass & UnionToIntersection<ReturnType<M[number]>>;
export {};
@@ -0,0 +1,20 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.compose = void 0;
/**
* Compose a class by applying mixins to it.
* The code is inspired by https://justinfagnani.com/2015/12/21/real-mixins-with-javascript-classes/, its
* just that I have added the support for static types too.
*/
const compose = (superclass, ...mixins) => {
return mixins.reduce((c, mixin) => mixin(c), superclass);
};
exports.compose = compose;
@@ -0,0 +1,4 @@
/**
* Returns an array of file paths from the given location.
*/
export declare function fsReadAll(location: string, callback?: (file: string) => boolean): string[];
@@ -0,0 +1,23 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fsReadAll = void 0;
const fs_readdir_recursive_1 = __importDefault(require("fs-readdir-recursive"));
const isScriptFile_1 = require("../isScriptFile");
/**
* Returns an array of file paths from the given location.
*/
function fsReadAll(location, callback) {
return (0, fs_readdir_recursive_1.default)(location).filter(typeof callback === 'function' ? callback : isScriptFile_1.isScriptFile);
}
exports.fsReadAll = fsReadAll;
@@ -0,0 +1,14 @@
export { default as cuid } from 'cuid';
export * as file from '@poppinss/file-generator';
export { base64 } from './base64';
export { compose, NormalizeConstructor } from './compose';
export { fsReadAll } from './fsReadAll';
export { interpolate } from './interpolate';
export { MessageBuilder } from './MessageBuilder';
export { ObjectBuilder } from './ObjectBuilder';
export { requireAll } from './requireAll';
export { resolveDir } from './resolveDir';
export { resolveFrom } from './resolveFrom';
export { safeEqual } from './safeEqual';
export * as string from './string';
export * as types from './types';
@@ -0,0 +1,62 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.types = exports.string = exports.safeEqual = exports.resolveFrom = exports.resolveDir = exports.requireAll = exports.ObjectBuilder = exports.MessageBuilder = exports.interpolate = exports.fsReadAll = exports.compose = exports.base64 = exports.file = exports.cuid = void 0;
var cuid_1 = require("cuid");
Object.defineProperty(exports, "cuid", { enumerable: true, get: function () { return __importDefault(cuid_1).default; } });
exports.file = __importStar(require("@poppinss/file-generator"));
var base64_1 = require("./base64");
Object.defineProperty(exports, "base64", { enumerable: true, get: function () { return base64_1.base64; } });
var compose_1 = require("./compose");
Object.defineProperty(exports, "compose", { enumerable: true, get: function () { return compose_1.compose; } });
var fsReadAll_1 = require("./fsReadAll");
Object.defineProperty(exports, "fsReadAll", { enumerable: true, get: function () { return fsReadAll_1.fsReadAll; } });
var interpolate_1 = require("./interpolate");
Object.defineProperty(exports, "interpolate", { enumerable: true, get: function () { return interpolate_1.interpolate; } });
var MessageBuilder_1 = require("./MessageBuilder");
Object.defineProperty(exports, "MessageBuilder", { enumerable: true, get: function () { return MessageBuilder_1.MessageBuilder; } });
var ObjectBuilder_1 = require("./ObjectBuilder");
Object.defineProperty(exports, "ObjectBuilder", { enumerable: true, get: function () { return ObjectBuilder_1.ObjectBuilder; } });
var requireAll_1 = require("./requireAll");
Object.defineProperty(exports, "requireAll", { enumerable: true, get: function () { return requireAll_1.requireAll; } });
var resolveDir_1 = require("./resolveDir");
Object.defineProperty(exports, "resolveDir", { enumerable: true, get: function () { return resolveDir_1.resolveDir; } });
var resolveFrom_1 = require("./resolveFrom");
Object.defineProperty(exports, "resolveFrom", { enumerable: true, get: function () { return resolveFrom_1.resolveFrom; } });
var safeEqual_1 = require("./safeEqual");
Object.defineProperty(exports, "safeEqual", { enumerable: true, get: function () { return safeEqual_1.safeEqual; } });
exports.string = __importStar(require("./string"));
exports.types = __importStar(require("./types"));
@@ -0,0 +1,7 @@
/**
* A simple function interpolate values inside curly braces.
*
* @example
* `interpolate('hello {{ username }}', { username: 'virk' })`
*/
export declare function interpolate(input: string, data: any): string;
@@ -0,0 +1,46 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.interpolate = void 0;
function uncurryThis(fn) {
return function (...args) {
return Function.call.apply(fn, args);
};
}
const hasOwnProperty = uncurryThis(Object.prototype.hasOwnProperty);
/**
* Parses prop
*/
function parseProp(data, key) {
const tokens = key.split('.');
while (tokens.length) {
if (data === null || typeof data !== 'object') {
return;
}
const token = tokens.shift();
data = hasOwnProperty(data, token) ? data[token] : undefined;
}
return data;
}
/**
* A simple function interpolate values inside curly braces.
*
* @example
* `interpolate('hello {{ username }}', { username: 'virk' })`
*/
function interpolate(input, data) {
return input.replace(/(\\)?{{(.*?)}}/g, (_, escapeChar, key) => {
if (escapeChar) {
return `{{${key}}}`;
}
return parseProp(data, key.trim());
});
}
exports.interpolate = interpolate;
@@ -0,0 +1,8 @@
/**
* Require all files from a given directory. The method automatically looks
* for files ending with `.ts`, `.js` and `.json`. Also files ending with
* `.d.ts` are ignored.
*/
export declare function requireAll(location: string, recursive?: boolean, optional?: boolean, filter?: (file: string) => boolean | string): {
[key: string]: any;
} | undefined;
@@ -0,0 +1,65 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.requireAll = void 0;
const path_1 = require("path");
const require_all_1 = __importDefault(require("require-all"));
const esmResolver_1 = require("../esmResolver");
const isScriptFile_1 = require("../isScriptFile");
/**
* Function to filter and keep script files only
*/
function fileFilter(file) {
return (0, isScriptFile_1.isScriptFile)(file);
}
/**
* Require all files from a given directory. The method automatically looks
* for files ending with `.ts`, `.js` and `.json`. Also files ending with
* `.d.ts` are ignored.
*/
function requireAll(location, recursive = true, optional = false, filter = fileFilter) {
try {
return (0, require_all_1.default)({
dirname: location,
recursive,
filter: (file) => {
let result = true;
/**
* Invoke user defined function
*/
if (typeof filter === 'function') {
result = filter(file);
}
/**
* Use the default file name when file is meant to
* be kept
*/
if (result === true) {
const ext = (0, path_1.extname)(file);
return file.replace(new RegExp(`${ext}$`), '');
}
return result;
},
resolve: esmResolver_1.esmResolver,
});
}
catch (error) {
if (error.code === 'ENOENT' && optional) {
return;
}
else {
throw error;
}
}
}
exports.requireAll = requireAll;
@@ -0,0 +1,5 @@
/**
* Resolves path to a given directory. The method is similar to `require.resolve`,
* but also works for directories with no `index.js` file.
*/
export declare function resolveDir(fromLocation: string, dirPath: string): string;
@@ -0,0 +1,46 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveDir = void 0;
const resolve_from_1 = __importDefault(require("resolve-from"));
const path_1 = require("path");
/**
* Resolves path to a given directory. The method is similar to `require.resolve`,
* but also works for directories with no `index.js` file.
*/
function resolveDir(fromLocation, dirPath) {
if ((0, path_1.isAbsolute)(dirPath)) {
return dirPath;
}
/**
* Relative paths are made by joining the baseDir
*/
if (dirPath.startsWith('./') || dirPath.startsWith(`.${path_1.sep}`)) {
return (0, path_1.join)(fromLocation, dirPath);
}
/**
* From here on, we are dealing with a package inside node module.
*/
let packageName = '';
const tokens = dirPath.replace(/\\/g, '/').split('/');
if (tokens.length && tokens[0].startsWith('@')) {
packageName = `${tokens.shift()}/`;
}
packageName += tokens.shift();
const resolved = resolve_from_1.default.silent(fromLocation, (0, path_1.join)(packageName, 'package.json'));
if (!resolved) {
throw new Error(`Cannot locate directory "${dirPath}"`);
}
return (0, path_1.join)((0, path_1.dirname)(resolved), tokens.join('/'));
}
exports.resolveDir = resolveDir;
@@ -0,0 +1,5 @@
/**
* Resolves module from a given directory. It is similar to `require.resolve`
* but carefull handles the absolute paths.
*/
export declare function resolveFrom(fromLocation: string, modulePath: string): string;
@@ -0,0 +1,27 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveFrom = void 0;
const path_1 = require("path");
const resolve_from_1 = __importDefault(require("resolve-from"));
/**
* Resolves module from a given directory. It is similar to `require.resolve`
* but carefull handles the absolute paths.
*/
function resolveFrom(fromLocation, modulePath) {
if ((0, path_1.isAbsolute)(modulePath)) {
return modulePath;
}
return (0, resolve_from_1.default)(fromLocation, modulePath);
}
exports.resolveFrom = resolveFrom;
@@ -0,0 +1,10 @@
declare type BufferSafeValue = ArrayBuffer | SharedArrayBuffer | number[] | string | {
valueOf(): string | object;
} | {
[Symbol.toPrimitive](hint: 'string'): string;
};
/**
* Generates a random string for a given size
*/
export declare function safeEqual<T extends BufferSafeValue>(value: T, comparisonValue: T): boolean;
export {};
@@ -0,0 +1,42 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeEqual = void 0;
const buffer_1 = require("buffer");
const crypto_1 = require("crypto");
/**
* Generates a random string for a given size
*/
function safeEqual(value, comparisonValue) {
if (typeof value === 'string' && typeof comparisonValue === 'string') {
/**
* The length of the main value to ensure that we compare equal strings
* against each other to get a constant time.
*/
const expectedLength = buffer_1.Buffer.byteLength(value);
/**
* Value A
*/
const valueBuffer = buffer_1.Buffer.alloc(expectedLength, 0, 'utf-8');
valueBuffer.write(value);
/**
* Value B
*/
const comparisonValueBuffer = buffer_1.Buffer.alloc(expectedLength, 0, 'utf-8');
comparisonValueBuffer.write(comparisonValue);
/**
* Ensure values are same and also have same length
*/
return ((0, crypto_1.timingSafeEqual)(valueBuffer, comparisonValueBuffer) &&
expectedLength === buffer_1.Buffer.byteLength(comparisonValue));
}
return (0, crypto_1.timingSafeEqual)(buffer_1.Buffer.from(value), buffer_1.Buffer.from(comparisonValue));
}
exports.safeEqual = safeEqual;
@@ -0,0 +1,124 @@
import { EncodeOptions } from 'he';
import { BytesOptions } from 'bytes';
export { default as toSlug } from 'slugify';
/**
* The method is a copy/paste from the "title-case" package. They have
* a dependency on "tslib", which I don't want.
*/
export declare function titleCase(input: string): string;
/**
* Define an irregular rule
*/
export declare function defineIrregularRule(singleValue: string, pluralValue: string): void;
/**
* Define uncountable rule
*/
export declare function defineUncountableRule(word: string): void;
/**
* Convert string to camelcase
*/
export declare function camelCase(value: string): string;
/**
* Convert string to snakecase
*/
export declare function snakeCase(value: string): string;
/**
* Convert string to dashcase
*/
export declare function dashCase(value: string, options?: {
capitalize?: boolean;
}): string;
/**
* Convert string to pascal case
*/
export declare function pascalCase(value: string): string;
/**
* Convert string to capital case
*/
export declare function capitalCase(value: string): string;
/**
* Convert string to sentence case
*/
export declare function sentenceCase(value: string): string;
/**
* Convert string to dot case
*/
export declare function dotCase(value: string): string;
/**
* Remove all sort of casing from the string
*/
export declare function noCase(value: string): string;
/**
* Pluralize a word
*/
export declare function pluralize(word: string): string;
/**
* Singularize a word
*/
export declare function singularize(word: string): string;
/**
* Truncate a sentence till a give limit of characters
*/
export declare function truncate(sentence: string, charactersLimit: number, options?: {
completeWords?: boolean;
suffix?: string;
}): string;
/**
* Same as truncate, but strips out the HTML
*/
export declare function excerpt(sentence: string, charactersLimit: number, options?: {
completeWords?: boolean;
suffix?: string;
}): string;
/**
* Condenses multiple whitespaces from a string
*/
export declare function condenseWhitespace(value: string): string;
/**
* Escape HTML entities
*/
export declare function escapeHTML(value: string, options?: {
encodeSymbols?: boolean;
}): string;
/**
* Encode symbols that arent printable ASCII symbols
*/
export declare function encodeSymbols(value: string, options?: EncodeOptions): string;
/**
* Convert array of values to a sentence
*/
export declare function toSentence(values: any[], options?: {
separator?: string;
pairSeparator?: string;
lastSeparator?: string;
}): string;
/**
* Convert a number to a human readable string
*/
export declare function prettyBytes(value: number, options?: BytesOptions): string;
/**
* Convert milliseconds to a human readable string
*/
export declare function prettyMs(value: number, options?: {
long: boolean;
}): string;
/**
* Find if a string is empty. Including any number of whitespaces
*/
export declare function isEmpty(value: string): boolean;
/**
* Ordinalize a give number or string
*/
export declare function ordinalize(value: string | number): string;
/**
* Converts unit expression to bytes
*/
export declare function toBytes(value: string | number): number;
/**
* Converts time expression to milliseconds
*/
export declare function toMs(value: string | number): number;
/**
* Generates a random string for a given size
*/
export declare function generateRandom(size: number): string;
@@ -0,0 +1,328 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateRandom = exports.toMs = exports.toBytes = exports.ordinalize = exports.isEmpty = exports.prettyMs = exports.prettyBytes = exports.toSentence = exports.encodeSymbols = exports.escapeHTML = exports.condenseWhitespace = exports.excerpt = exports.truncate = exports.singularize = exports.pluralize = exports.noCase = exports.dotCase = exports.sentenceCase = exports.capitalCase = exports.pascalCase = exports.dashCase = exports.snakeCase = exports.camelCase = exports.defineUncountableRule = exports.defineIrregularRule = exports.titleCase = exports.toSlug = void 0;
const ms_1 = __importDefault(require("ms"));
const truncatise_1 = __importDefault(require("truncatise"));
const crypto_1 = require("crypto");
const he_1 = __importDefault(require("he"));
const changeCase = __importStar(require("change-case"));
const bytes_1 = __importDefault(require("bytes"));
const pluralize_1 = require("pluralize");
var slugify_1 = require("slugify");
Object.defineProperty(exports, "toSlug", { enumerable: true, get: function () { return __importDefault(slugify_1).default; } });
const SMALL_WORDS = /\b(?:an?d?|a[st]|because|but|by|en|for|i[fn]|neither|nor|o[fnr]|only|over|per|so|some|tha[tn]|the|to|up|upon|vs?\.?|versus|via|when|with|without|yet)\b/i;
const TOKENS = /[^\s:–—-]+|./g;
const WHITESPACE = /\s/;
const IS_MANUAL_CASE = /.(?=[A-Z]|\..)/;
const ALPHANUMERIC_PATTERN = /[A-Za-z0-9\u00C0-\u00FF]/;
/**
* The method is a copy/paste from the "title-case" package. They have
* a dependency on "tslib", which I don't want.
*/
function titleCase(input) {
let output = '';
let result;
while ((result = TOKENS.exec(input)) !== null) {
const { 0: token, index } = result;
if (!IS_MANUAL_CASE.test(token) &&
(!SMALL_WORDS.test(token) || index === 0 || index + token.length === input.length) &&
(input.charAt(index + token.length) !== ':' ||
WHITESPACE.test(input.charAt(index + token.length + 1)))) {
output += token.replace(ALPHANUMERIC_PATTERN, (char) => char.toUpperCase());
continue;
}
output += token;
}
return output;
}
exports.titleCase = titleCase;
/**
* Normalizes base64 string by removing special chars and padding
*/
function normalizeBase64(value) {
return value.replace(/\+/g, '-').replace(/\//g, '_').replace(/\=/g, '');
}
/**
* Define an irregular rule
*/
function defineIrregularRule(singleValue, pluralValue) {
(0, pluralize_1.addIrregularRule)(singleValue, pluralValue);
}
exports.defineIrregularRule = defineIrregularRule;
/**
* Define uncountable rule
*/
function defineUncountableRule(word) {
(0, pluralize_1.addUncountableRule)(word);
}
exports.defineUncountableRule = defineUncountableRule;
/**
* Convert string to camelcase
*/
function camelCase(value) {
return changeCase.camelCase(value);
}
exports.camelCase = camelCase;
/**
* Convert string to snakecase
*/
function snakeCase(value) {
return changeCase.snakeCase(value);
}
exports.snakeCase = snakeCase;
/**
* Convert string to dashcase
*/
function dashCase(value, options) {
if (options && options.capitalize) {
return changeCase.headerCase(value);
}
return changeCase.paramCase(value);
}
exports.dashCase = dashCase;
/**
* Convert string to pascal case
*/
function pascalCase(value) {
return changeCase.pascalCase(value);
}
exports.pascalCase = pascalCase;
/**
* Convert string to capital case
*/
function capitalCase(value) {
return changeCase.capitalCase(value);
}
exports.capitalCase = capitalCase;
/**
* Convert string to sentence case
*/
function sentenceCase(value) {
return changeCase.sentenceCase(value);
}
exports.sentenceCase = sentenceCase;
/**
* Convert string to dot case
*/
function dotCase(value) {
return changeCase.dotCase(value);
}
exports.dotCase = dotCase;
/**
* Remove all sort of casing from the string
*/
function noCase(value) {
return changeCase.noCase(value);
}
exports.noCase = noCase;
/**
* Pluralize a word
*/
function pluralize(word) {
return (0, pluralize_1.plural)(word);
}
exports.pluralize = pluralize;
/**
* Singularize a word
*/
function singularize(word) {
return (0, pluralize_1.singular)(word);
}
exports.singularize = singularize;
/**
* Truncate a sentence till a give limit of characters
*/
function truncate(sentence, charactersLimit, options) {
return (0, truncatise_1.default)(sentence, {
TruncateLength: charactersLimit,
/**
* Do not complete words when "completeWords" is not explicitly set
* to true
*/
Strict: options && options.completeWords === true ? false : true,
StripHTML: false,
TruncateBy: 'characters',
Suffix: options && options.suffix,
});
}
exports.truncate = truncate;
/**
* Same as truncate, but strips out the HTML
*/
function excerpt(sentence, charactersLimit, options) {
return (0, truncatise_1.default)(sentence, {
TruncateLength: charactersLimit,
/**
* Do not complete words when "completeWords" is not explicitly set
* to true
*/
Strict: options && options.completeWords === true ? false : true,
StripHTML: true,
TruncateBy: 'characters',
Suffix: options && options.suffix,
});
}
exports.excerpt = excerpt;
/**
* Condenses multiple whitespaces from a string
*/
function condenseWhitespace(value) {
return value.trim().replace(/\s{2,}/g, ' ');
}
exports.condenseWhitespace = condenseWhitespace;
/**
* Escape HTML entities
*/
function escapeHTML(value, options) {
value = he_1.default.escape(value);
if (options && options.encodeSymbols) {
value = encodeSymbols(value, { allowUnsafeSymbols: true });
}
return value;
}
exports.escapeHTML = escapeHTML;
/**
* Encode symbols that arent printable ASCII symbols
*/
function encodeSymbols(value, options) {
return he_1.default.encode(value, options);
}
exports.encodeSymbols = encodeSymbols;
/**
* Convert array of values to a sentence
*/
function toSentence(values, options) {
/**
* Empty array
*/
if (values.length === 0) {
return '';
}
/**
* Just one item
*/
if (values.length === 1) {
return values[0];
}
/**
* Giving some love to two items, so that one can use oxford comma's
*/
if (values.length === 2) {
return `${values[0]}${options?.pairSeparator || ' and '}${values[1]}`;
}
const normalized = Object.assign({ separator: ', ', lastSeparator: ', and ' }, options);
/**
* Make sentence
*/
return `${values.slice(0, -1).join(normalized.separator)}${normalized.lastSeparator}${values[values.length - 1]}`;
}
exports.toSentence = toSentence;
/**
* Convert a number to a human readable string
*/
function prettyBytes(value, options) {
return bytes_1.default.format(value, options);
}
exports.prettyBytes = prettyBytes;
/**
* Convert milliseconds to a human readable string
*/
function prettyMs(value, options) {
return (0, ms_1.default)(value, options);
}
exports.prettyMs = prettyMs;
/**
* Find if a string is empty. Including any number of whitespaces
*/
function isEmpty(value) {
return value.trim().length === 0;
}
exports.isEmpty = isEmpty;
/**
* Ordinalize a give number or string
*/
function ordinalize(value) {
const transformedValue = Math.abs(typeof value === 'string' ? parseInt(value) : value);
if (!Number.isFinite(transformedValue) || Number.isNaN(transformedValue)) {
throw new Error('Cannot ordinalize NAN or infinite numbers');
}
const percent = transformedValue % 100;
if (percent >= 10 && percent <= 20) {
return `${value}th`;
}
const decimal = transformedValue % 10;
switch (decimal) {
case 1:
return `${value}st`;
case 2:
return `${value}nd`;
case 3:
return `${value}rd`;
default:
return `${value}th`;
}
}
exports.ordinalize = ordinalize;
/**
* Converts unit expression to bytes
*/
function toBytes(value) {
if (typeof value === 'number') {
return value;
}
return bytes_1.default.parse(value);
}
exports.toBytes = toBytes;
/**
* Converts time expression to milliseconds
*/
function toMs(value) {
if (typeof value === 'number') {
return value;
}
return (0, ms_1.default)(value);
}
exports.toMs = toMs;
/**
* Generates a random string for a given size
*/
function generateRandom(size) {
const bits = (size + 1) * 6;
const buffer = (0, crypto_1.randomBytes)(Math.ceil(bits / 8));
return normalizeBase64(buffer.toString('base64')).slice(0, size);
}
exports.generateRandom = generateRandom;
@@ -0,0 +1,86 @@
/// <reference types="node" />
/**
* Lookup the type for a given value
*/
export declare function lookup(value: any): 'undefined' | 'null' | 'boolean' | 'buffer' | 'number' | 'string' | 'arguments' | 'object' | 'date' | 'array' | 'regexp' | 'error' | 'function' | 'class' | 'generatorfunction' | 'symbol' | 'map' | 'weakmap' | 'set' | 'weakset' | 'int8array' | 'uint8array' | 'uint8clampedarray' | 'int16array' | 'uint16array' | 'int32array' | 'uint32array' | 'float32array' | 'float64array';
/**
* Find if a given value is undefined
*/
export declare function isUndefined(value: any): value is undefined;
/**
* Find if a given value is null
*/
export declare function isNull(value: any): value is null;
/**
* Find if a given value is a boolean
*/
export declare function isBoolean(value: any): value is boolean;
/**
* Find if a given value is a buffer
*/
export declare function isBuffer(value: any): value is Buffer;
/**
* Find if a given value is a number
*/
export declare function isNumber(value: any): value is number;
/**
* Find if a given value is a string
*/
export declare function isString(value: any): value is string;
/**
* Find if a given value is function arguments
*/
export declare function isArguments(value: any): boolean;
/**
* Find if a given value is a plain object
*/
export declare function isObject(value: any): boolean;
/**
* Find if a given value is a date instance
*/
export declare function isDate(value: any): value is Date;
/**
* Find if a given value is an array
*/
export declare function isArray(value: any): value is any[];
/**
* Find if a given value is an regularExpression
*/
export declare function isRegexp(value: any): value is RegExp;
/**
* Find if a given value is an instance of Error class
*/
export declare function isError(value: any): boolean;
/**
* Find if a given value is a Function
*/
export declare function isFunction(value: any): value is Function;
/**
* Find if a given value is a class. Uses regular expression, since there
* is no way to natively distinguish a class and a function in Javascript
*/
export declare function isClass(value: any): boolean;
/**
* Find if a value is an integer or not
*/
export declare function isInteger(value: number): value is number;
/**
* Find if a value is float value or not. The values with more than
* zero remainder returns true
*/
export declare function isFloat(value: number): value is number;
/**
* Find if the value has given decimal place or not.
*
* Since there is no direct way in Javascript to check for decimal place. We make
* use of regex to find it out.
*
* Numeric values are converted to string by calling `value.toString()` before
* testing it against the regex.
*
* If this method returns `true`, then you can safely parse the string with `parseFloat`
* method.
*/
export declare function isDecimal(value: string | number, options?: {
decimalPlaces?: string;
}): boolean;
@@ -0,0 +1,161 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isDecimal = exports.isFloat = exports.isInteger = exports.isClass = exports.isFunction = exports.isError = exports.isRegexp = exports.isArray = exports.isDate = exports.isObject = exports.isArguments = exports.isString = exports.isNumber = exports.isBuffer = exports.isBoolean = exports.isNull = exports.isUndefined = exports.lookup = void 0;
const kind_of_1 = __importDefault(require("kind-of"));
const toString = Function.prototype.toString;
/**
* Lookup the type for a given value
*/
function lookup(value) {
const kind = (0, kind_of_1.default)(value);
if (kind === 'function' && /^class\s/.test(toString.call(value))) {
return 'class';
}
return kind;
}
exports.lookup = lookup;
/**
* Find if a given value is undefined
*/
function isUndefined(value) {
return lookup(value) === 'undefined';
}
exports.isUndefined = isUndefined;
/**
* Find if a given value is null
*/
function isNull(value) {
return lookup(value) === 'null';
}
exports.isNull = isNull;
/**
* Find if a given value is a boolean
*/
function isBoolean(value) {
return lookup(value) === 'boolean';
}
exports.isBoolean = isBoolean;
/**
* Find if a given value is a buffer
*/
function isBuffer(value) {
return lookup(value) === 'buffer';
}
exports.isBuffer = isBuffer;
/**
* Find if a given value is a number
*/
function isNumber(value) {
return lookup(value) === 'number';
}
exports.isNumber = isNumber;
/**
* Find if a given value is a string
*/
function isString(value) {
return lookup(value) === 'string';
}
exports.isString = isString;
/**
* Find if a given value is function arguments
*/
function isArguments(value) {
return lookup(value) === 'arguments';
}
exports.isArguments = isArguments;
/**
* Find if a given value is a plain object
*/
function isObject(value) {
return lookup(value) === 'object';
}
exports.isObject = isObject;
/**
* Find if a given value is a date instance
*/
function isDate(value) {
return lookup(value) === 'date';
}
exports.isDate = isDate;
/**
* Find if a given value is an array
*/
function isArray(value) {
return lookup(value) === 'array';
}
exports.isArray = isArray;
/**
* Find if a given value is an regularExpression
*/
function isRegexp(value) {
return lookup(value) === 'regexp';
}
exports.isRegexp = isRegexp;
/**
* Find if a given value is an instance of Error class
*/
function isError(value) {
return lookup(value) === 'error';
}
exports.isError = isError;
/**
* Find if a given value is a Function
*/
function isFunction(value) {
return lookup(value) === 'function';
}
exports.isFunction = isFunction;
/**
* Find if a given value is a class. Uses regular expression, since there
* is no way to natively distinguish a class and a function in Javascript
*/
function isClass(value) {
return lookup(value) === 'class';
}
exports.isClass = isClass;
/**
* Find if a value is an integer or not
*/
function isInteger(value) {
return Number.isInteger(value);
}
exports.isInteger = isInteger;
/**
* Find if a value is float value or not. The values with more than
* zero remainder returns true
*/
function isFloat(value) {
return value !== (value | 0);
}
exports.isFloat = isFloat;
/**
* Find if the value has given decimal place or not.
*
* Since there is no direct way in Javascript to check for decimal place. We make
* use of regex to find it out.
*
* Numeric values are converted to string by calling `value.toString()` before
* testing it against the regex.
*
* If this method returns `true`, then you can safely parse the string with `parseFloat`
* method.
*/
function isDecimal(value, options) {
if (typeof value === 'number') {
value = value.toString();
}
const decimalPlaces = (options && options.decimalPlaces) || '1,';
return new RegExp(`^[-+]?([0-9]+)?(\\.[0-9]{${decimalPlaces}})$`).test(value);
}
exports.isDecimal = isDecimal;
@@ -0,0 +1,20 @@
/**
* A simple class to raise consistent exceptions for invalid config
* for driver based implementations.
*/
export declare class ManagerConfigValidator {
private config;
private serviceName;
private configLocation;
constructor(config: any, serviceName: string, configLocation: string);
/**
* Validates that the default key name is defined inside the config
* for a given module/service
*/
validateDefault(keyName: string): void;
/**
* Validates that the list to ensure that is is defined and the default
* key name is also part of the list.
*/
validateList(listName: string, keyName: string): void;
}
@@ -0,0 +1,55 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ManagerConfigValidator = void 0;
const Exception_1 = require("./Exception");
/**
* A simple class to raise consistent exceptions for invalid config
* for driver based implementations.
*/
class ManagerConfigValidator {
constructor(config, serviceName, configLocation) {
this.config = config;
this.serviceName = serviceName;
this.configLocation = configLocation;
}
/**
* Validates that the default key name is defined inside the config
* for a given module/service
*/
validateDefault(keyName) {
if (!this.config[keyName]) {
throw new Exception_1.Exception([
`Invalid "${this.serviceName}" config. Missing value for "${keyName}".`,
`Make sure to set it inside the "${this.configLocation}" file`,
].join(' '));
}
}
/**
* Validates that the list to ensure that is is defined and the default
* key name is also part of the list.
*/
validateList(listName, keyName) {
if (!this.config[listName]) {
throw new Exception_1.Exception([
`Invalid "${this.serviceName}" config. Missing value for "${listName}".`,
`Make sure to set it inside the "${this.configLocation}" file`,
].join(' '));
}
const defaultValue = this.config[keyName];
if (!this.config[listName][defaultValue]) {
throw new Exception_1.Exception([
`Invalid "${this.serviceName}" config. "${defaultValue}" is not defined inside "${listName}".`,
`Make sure to set it inside the "${this.configLocation}" file`,
].join(' '));
}
}
}
exports.ManagerConfigValidator = ManagerConfigValidator;
@@ -0,0 +1,11 @@
declare type Constructor = new (...args: any[]) => any;
declare type AbstractConstructor = abstract new (...args: any[]) => any;
/**
* Define static properties on a class with inheritance in play.
*/
export declare function defineStaticProperty<T extends Constructor | AbstractConstructor, Prop extends keyof T>(self: T, BaseClass: Constructor | AbstractConstructor, { propertyName, defaultValue, strategy, }: {
propertyName: Prop;
defaultValue: T[Prop];
strategy: 'inherit' | 'define' | ((value: T[Prop]) => T[Prop]);
}): void;
export {};
@@ -0,0 +1,57 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineStaticProperty = void 0;
const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
/**
* Define static properties on a class with inheritance in play.
*/
function defineStaticProperty(self, BaseClass, { propertyName, defaultValue, strategy, }) {
if (!self.hasOwnProperty(propertyName)) {
/**
* Class is inhering the base class directly and hence we don't have to
* copy any properties
*/
if (Object.getPrototypeOf(self.prototype) === BaseClass.prototype || strategy === 'define') {
Object.defineProperty(self, propertyName, {
value: defaultValue,
configurable: true,
enumerable: true,
writable: true,
});
return;
}
/**
* Class is inherting another sub class. We must copy the values to the self
* class, otherwise mutating them inside the self class will be reflected
* on the base class.
*/
const value = self[propertyName];
if (value === undefined) {
Object.defineProperty(self, propertyName, {
value: defaultValue,
configurable: true,
enumerable: true,
writable: true,
});
return;
}
Object.defineProperty(self, propertyName, {
value: typeof strategy === 'function' ? strategy(value) : (0, cloneDeep_1.default)(value),
configurable: true,
enumerable: true,
writable: true,
});
}
}
exports.defineStaticProperty = defineStaticProperty;
@@ -0,0 +1,5 @@
/**
* Handles ESM `default` exports and common js vanilla exports. The `default`
* exports are only entertained, when `esmEnabled` is set to true.
*/
export declare function esmRequire(filePath: string): any;
@@ -0,0 +1,20 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.esmRequire = void 0;
const esmResolver_1 = require("./esmResolver");
/**
* Handles ESM `default` exports and common js vanilla exports. The `default`
* exports are only entertained, when `esmEnabled` is set to true.
*/
function esmRequire(filePath) {
return (0, esmResolver_1.esmResolver)(require(filePath));
}
exports.esmRequire = esmRequire;
@@ -0,0 +1 @@
export declare function esmResolver(output: any): any;
@@ -0,0 +1,15 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.esmResolver = void 0;
function esmResolver(output) {
return output && output.__esModule && output.default ? output.default : output;
}
exports.esmResolver = esmResolver;
@@ -0,0 +1,2 @@
export declare type ReplacerFn = (this: any, key: string, value: any) => any;
export declare function stringify(obj: any, replacer?: ReplacerFn, spacer?: string | number): any;
@@ -0,0 +1,101 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringify = void 0;
/**
* Exact copy of https://github.com/davidmarkclements/fast-safe-stringify/blob/master/index.js
* with a few changes that were introduced in https://github.com/davidmarkclements/fast-safe-stringify/pull/52 PR.
*/
const arr = [];
const replacerStack = [];
// Regular stringify
function stringify(obj, replacer, spacer) {
decirc(obj, '', [], undefined);
let res;
if (replacerStack.length === 0) {
res = JSON.stringify(obj, replacer, spacer);
}
else {
res = JSON.stringify(obj, replaceGetterValues(replacer), spacer);
}
while (arr.length !== 0) {
var part = arr.pop();
if (part.length === 4) {
Object.defineProperty(part[0], part[1], part[3]);
}
else {
part[0][part[1]] = part[2];
}
}
return res;
}
exports.stringify = stringify;
function decirc(val, k, stack, parent) {
let i;
if (typeof val === 'object' && val !== null) {
for (i = 0; i < stack.length; i++) {
if (stack[i] === val) {
let propertyDescriptor = Object.getOwnPropertyDescriptor(parent, k);
if (propertyDescriptor.get !== undefined) {
if (propertyDescriptor.configurable) {
Object.defineProperty(parent, k, { value: '[Circular]' });
arr.push([parent, k, val, propertyDescriptor]);
}
else {
replacerStack.push([val, k]);
}
}
else {
parent[k] = '[Circular]';
arr.push([parent, k, val]);
}
return;
}
}
stack.push(val);
// Optimize for Arrays. Big arrays could kill the performance otherwise!
if (Array.isArray(val)) {
for (i = 0; i < val.length; i++) {
decirc(val[i], i, stack, val);
}
}
else {
var keys = Object.keys(val);
for (i = 0; i < keys.length; i++) {
var key = keys[i];
decirc(val[key], key, stack, val);
}
}
stack.pop();
}
}
// wraps replacer function to handle values we couldn't replace
// and mark them as [Circular]
function replaceGetterValues(replacer) {
replacer =
replacer !== undefined
? replacer
: function (_, v) {
return v;
};
return function (key, val) {
if (replacerStack.length > 0) {
for (var i = 0; i < replacerStack.length; i++) {
var part = replacerStack[i];
if (part[1] === key && part[0] === val) {
val = '[Circular]';
replacerStack.splice(i, 1);
break;
}
}
}
return replacer.call(this, key, val);
};
}
@@ -0,0 +1 @@
export { flattie as flatten } from 'flattie';
@@ -0,0 +1,13 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.flatten = void 0;
var flattie_1 = require("flattie");
Object.defineProperty(exports, "flatten", { enumerable: true, get: function () { return flattie_1.flattie; } });
@@ -0,0 +1,5 @@
/**
* Returns `true` when file ends with `.js`, `.json` or
* `.ts` but not `.d.ts`.
*/
export declare function isScriptFile(file: string): boolean;
@@ -0,0 +1,28 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.isScriptFile = void 0;
const path_1 = require("path");
const JS_MODULES = ['.js', '.json'];
/**
* Returns `true` when file ends with `.js`, `.json` or
* `.ts` but not `.d.ts`.
*/
function isScriptFile(file) {
const ext = (0, path_1.extname)(file);
if (JS_MODULES.includes(ext)) {
return true;
}
if (ext === '.ts' && !file.endsWith('.d.ts')) {
return true;
}
return false;
}
exports.isScriptFile = isScriptFile;
@@ -0,0 +1,13 @@
/// <reference path="../../types/lodash.types.d.ts" />
export { default as pick } from 'lodash/pick';
export { default as omit } from 'lodash/omit';
export { default as has } from 'lodash/has';
export { default as get } from 'lodash/get';
export { default as set } from 'lodash/set';
export { default as unset } from 'lodash/unset';
export { default as mergeWith } from 'lodash/mergeWith';
export { default as merge } from 'lodash/merge';
export { default as size } from 'lodash/size';
export { default as clone } from 'lodash/clone';
export { default as cloneDeep } from 'lodash/cloneDeep';
export { default as toPath } from 'lodash/toPath';
@@ -0,0 +1,39 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.toPath = exports.cloneDeep = exports.clone = exports.size = exports.merge = exports.mergeWith = exports.unset = exports.set = exports.get = exports.has = exports.omit = exports.pick = void 0;
/// <reference path="../types/lodash.types.d.ts" />
var pick_1 = require("lodash/pick");
Object.defineProperty(exports, "pick", { enumerable: true, get: function () { return __importDefault(pick_1).default; } });
var omit_1 = require("lodash/omit");
Object.defineProperty(exports, "omit", { enumerable: true, get: function () { return __importDefault(omit_1).default; } });
var has_1 = require("lodash/has");
Object.defineProperty(exports, "has", { enumerable: true, get: function () { return __importDefault(has_1).default; } });
var get_1 = require("lodash/get");
Object.defineProperty(exports, "get", { enumerable: true, get: function () { return __importDefault(get_1).default; } });
var set_1 = require("lodash/set");
Object.defineProperty(exports, "set", { enumerable: true, get: function () { return __importDefault(set_1).default; } });
var unset_1 = require("lodash/unset");
Object.defineProperty(exports, "unset", { enumerable: true, get: function () { return __importDefault(unset_1).default; } });
var mergeWith_1 = require("lodash/mergeWith");
Object.defineProperty(exports, "mergeWith", { enumerable: true, get: function () { return __importDefault(mergeWith_1).default; } });
var merge_1 = require("lodash/merge");
Object.defineProperty(exports, "merge", { enumerable: true, get: function () { return __importDefault(merge_1).default; } });
var size_1 = require("lodash/size");
Object.defineProperty(exports, "size", { enumerable: true, get: function () { return __importDefault(size_1).default; } });
var clone_1 = require("lodash/clone");
Object.defineProperty(exports, "clone", { enumerable: true, get: function () { return __importDefault(clone_1).default; } });
var cloneDeep_1 = require("lodash/cloneDeep");
Object.defineProperty(exports, "cloneDeep", { enumerable: true, get: function () { return __importDefault(cloneDeep_1).default; } });
var toPath_1 = require("lodash/toPath");
Object.defineProperty(exports, "toPath", { enumerable: true, get: function () { return __importDefault(toPath_1).default; } });
@@ -0,0 +1,5 @@
/**
* Copied directly from https://github.com/nuxt-contrib/destr/blob/master/src/index.ts but
* instead raises the malformed JSON exceptions vs swallowing them
*/
export declare function safeParse(val: string, reviver?: (this: any, jsonKey: string, jsonValue: any) => any): any;
@@ -0,0 +1,42 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeParse = void 0;
// https://github.com/fastify/secure-json-parse
// https://github.com/hapijs/bourne
const suspectProtoRx = /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/;
const suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
const JsonSigRx = /^["{[]|^-?[0-9][0-9.]*$/;
function jsonParseTransform(key, value, reviver) {
if (key === '__proto__' || key === 'constructor') {
return;
}
return reviver ? reviver(key, value) : value;
}
/**
* Copied directly from https://github.com/nuxt-contrib/destr/blob/master/src/index.ts but
* instead raises the malformed JSON exceptions vs swallowing them
*/
function safeParse(val, reviver) {
if (typeof val !== 'string') {
return val;
}
if (val === 'null') {
return null;
}
if (!JsonSigRx.test(val)) {
return val;
}
if (suspectProtoRx.test(val) || suspectConstructorRx.test(val)) {
return JSON.parse(val, (key, value) => jsonParseTransform(key, value, reviver));
}
return JSON.parse(val, reviver);
}
exports.safeParse = safeParse;
@@ -0,0 +1,5 @@
import { ReplacerFn } from './fast-safe-stringify';
/**
* Safely stringifies a Javascript native value
*/
export declare function safeStringify(value: any, replacer?: ReplacerFn, space?: string | number): string;
@@ -0,0 +1,39 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeStringify = void 0;
const fast_safe_stringify_1 = require("./fast-safe-stringify");
/**
* Replacer to handle bigints and remove Circular values all together
*/
function jsonStringifyReplacer(replacer, removeCircular) {
return function (key, value) {
if (removeCircular && value === '[Circular]') {
return;
}
const val = replacer ? replacer.call(this, key, value) : value;
if (typeof val === 'bigint') {
return val.toString();
}
return val;
};
}
/**
* Safely stringifies a Javascript native value
*/
function safeStringify(value, replacer, space) {
try {
return JSON.stringify(value, jsonStringifyReplacer(replacer, false), space);
}
catch {
return (0, fast_safe_stringify_1.stringify)(value, jsonStringifyReplacer(replacer, true), space);
}
}
exports.safeStringify = safeStringify;
@@ -0,0 +1,5 @@
/**
* Convert windows path to unix.
* Copied from https://github.com/sindresorhus/slash as the package is ESM only
*/
export declare function slash(filePath: string): string;
@@ -0,0 +1,24 @@
"use strict";
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.slash = void 0;
/**
* Convert windows path to unix.
* Copied from https://github.com/sindresorhus/slash as the package is ESM only
*/
function slash(filePath) {
const isExtendedLengthPath = /^\\\\\?\\/.test(filePath);
const hasNonAscii = /[^\u0000-\u0080]+/.test(filePath); // eslint-disable-line no-control-regex
if (isExtendedLengthPath || hasNonAscii) {
return filePath;
}
return filePath.replace(/\\/g, '/');
}
exports.slash = slash;
+151
View File
@@ -0,0 +1,151 @@
{
"name": "@poppinss/utils",
"version": "4.0.4",
"description": "Handy utilities for repetitive work",
"main": "build/index.js",
"files": [
"build/src",
"build/index.d.ts",
"build/index.js",
"types",
"build/helpers.d.ts",
"build/helpers.js"
],
"scripts": {
"mrm": "mrm --preset=@adonisjs/mrm-preset",
"pretest": "npm run lint",
"test": "node .bin/test.js",
"clean": "del build",
"compile": "npm run lint && npm run clean && tsc",
"build": "npm run compile",
"commit": "git-cz",
"release": "np --message=\"chore(release): %s\"",
"version": "npm run build",
"format": "prettier --write .",
"prepublishOnly": "npm run build",
"lint": "eslint . --ext=.ts",
"sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json poppinss/utils"
},
"keywords": [
"utils"
],
"author": "virk,poppinss",
"license": "MIT",
"devDependencies": {
"@adonisjs/mrm-preset": "^5.0.3",
"@adonisjs/require-ts": "^2.0.11",
"@poppinss/dev-utils": "^2.0.3",
"@types/fs-readdir-recursive": "^1.0.0",
"@types/lodash": "^4.14.181",
"@types/ms": "^0.7.31",
"@types/node": "^17.0.23",
"@types/pluralize": "0.0.29",
"@types/require-all": "^3.0.3",
"del-cli": "^4.0.1",
"doctoc": "^2.1.0",
"eslint": "^8.13.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-adonis": "^2.1.0",
"eslint-plugin-prettier": "^4.0.0",
"github-label-sync": "^2.2.0",
"husky": "^7.0.4",
"japa": "^4.0.0",
"mrm": "^4.0.0",
"np": "^7.6.1",
"prettier": "^2.6.2",
"typescript": "^4.6.3"
},
"nyc": {
"exclude": [
"test"
],
"extension": [
".ts"
]
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
},
"np": {
"contents": ".",
"anyBranch": false
},
"dependencies": {
"@poppinss/file-generator": "^1.0.2",
"@types/bytes": "^3.1.1",
"@types/he": "^1.1.2",
"bytes": "^3.1.2",
"change-case": "^4.1.2",
"cuid": "^2.1.8",
"flattie": "^1.1.0",
"fs-readdir-recursive": "^1.1.0",
"he": "^1.2.0",
"kind-of": "^6.0.3",
"lodash": "^4.17.21",
"ms": "^2.1.3",
"pluralize": "^8.0.0",
"require-all": "^3.0.0",
"resolve-from": "^5.0.0",
"slugify": "^1.6.5",
"truncatise": "0.0.8"
},
"directories": {
"doc": "docs",
"test": "test"
},
"repository": {
"type": "git",
"url": "git+https://github.com/poppinss/utils.git"
},
"bugs": {
"url": "https://github.com/poppinss/utils/issues"
},
"homepage": "https://github.com/poppinss/utils#readme",
"eslintConfig": {
"extends": [
"plugin:adonis/typescriptPackage",
"prettier",
"prettier"
],
"plugins": [
"prettier",
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
},
"eslintIgnore": [
"build"
],
"prettier": {
"trailingComma": "es5",
"semi": false,
"singleQuote": true,
"useTabs": false,
"quoteProps": "consistent",
"bracketSpacing": true,
"arrowParens": "always",
"printWidth": 100
},
"mrmConfig": {
"core": false,
"license": "MIT",
"services": [
"github-actions"
],
"minNodeVersion": "16.13.1",
"probotApps": [
"stale",
"lock"
],
"runGhActionsOnWindows": true
}
}
@@ -0,0 +1,65 @@
/*
* @poppinss/utils
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
type PropertyName = string | number | symbol
type PropertyNames = PropertyName | ReadonlyArray<PropertyName>
declare module 'lodash/pick' {
export default function pick<T>(
object: T | null | undefined,
...props: Array<PropertyNames>
): Partial<T>
}
declare module 'lodash/omit' {
export default function omit<T extends object>(
object: T | null | undefined,
...paths: Array<PropertyNames>
): Partial<T>
}
declare module 'lodash/has' {
export default function has<T>(object: T, path: PropertyNames): boolean
}
declare module 'lodash/get' {
export default function get(object: any, path: PropertyNames, defaultValue?: any): any
}
declare module 'lodash/set' {
export default function set(object: any, path: PropertyNames, value: any): any
}
declare module 'lodash/unset' {
export default function unset(object: any, path: PropertyNames): boolean
}
declare module 'lodash/mergeWith' {
export default function mergeWith(object: any, ...otherArgs: any[]): any
}
declare module 'lodash/merge' {
export default function merge(object: any, ...otherArgs: any[]): any
}
declare module 'lodash/size' {
export default function size(collection: object | string | null | undefined): number
}
declare module 'lodash/clone' {
export default function clone<T>(value: T): T
}
declare module 'lodash/cloneDeep' {
export default function cloneDeep<T>(value: T): T
}
declare module 'lodash/toPath' {
export default function toPath(value: any): string[]
}
+176
View File
@@ -0,0 +1,176 @@
{
"name": "@adonisjs/shield",
"version": "7.1.1",
"description": "A middleware for AdonisJS to keep web applications secure from common web attacks",
"main": "build/providers/ShieldProvider.js",
"files": [
"build/adonis-typings",
"build/providers",
"build/src",
"build/templates",
"build/standalone.d.ts",
"build/standalone.js",
"build/instructions.md"
],
"typings": "./build/adonis-typings/index.d.ts",
"scripts": {
"mrm": "mrm --preset=@adonisjs/mrm-preset",
"pretest": "npm run lint",
"test": "node -r @adonisjs/require-ts/build/register bin/test.ts",
"prepublishOnly": "npm run build",
"clean": "del-cli build",
"copy:files": "copyfiles \"templates/**/*.txt\" build && npm run copy:instructions_md",
"copy:instructions_md": "copyfiles \"instructions.md\" build",
"compile": "npm run lint && npm run clean && tsc && npm run copy:files",
"build": "npm run compile",
"commit": "git-cz",
"release": "np --message=\"chore(release): %s\"",
"version": "npm run build",
"lint": "eslint . --ext=.ts",
"format": "prettier --write .",
"sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json adonisjs/shield"
},
"keywords": [
"adonisjs",
"adonis",
"web-security",
"csrf",
"csp"
],
"peerDependencies": {
"@adonisjs/core": "^5.7.0",
"@adonisjs/session": "^6.2.0",
"@adonisjs/view": "^6.1.0"
},
"peerDependenciesMeta": {
"@adonisjs/view": {
"optional": true
}
},
"author": "virk",
"license": "MIT",
"devDependencies": {
"@adonisjs/core": "^5.9.0",
"@adonisjs/mrm-preset": "^5.0.3",
"@adonisjs/require-ts": "^2.0.13",
"@adonisjs/session": "^6.4.0",
"@adonisjs/view": "^6.2.0",
"@japa/assert": "^1.4.1",
"@japa/preset-adonis": "^1.2.0",
"@japa/run-failed-tests": "^1.1.1",
"@japa/runner": "^2.5.1",
"@japa/spec-reporter": "^1.3.3",
"@poppinss/dev-utils": "^2.0.3",
"@types/csrf": "^3.1.0",
"@types/node": "^18.7.6",
"commitizen": "^4.3.0",
"copyfiles": "^2.4.1",
"cz-conventional-changelog": "^3.3.0",
"del-cli": "^5.0.0",
"eslint": "^8.42.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-adonis": "^2.1.1",
"eslint-plugin-prettier": "^4.2.1",
"github-label-sync": "^2.3.1",
"husky": "^8.0.3",
"mrm": "^4.1.14",
"np": "^7.6.2",
"prettier": "^2.8.8",
"reflect-metadata": "^0.1.13",
"typescript": "^5.1.3"
},
"dependencies": {
"@poppinss/utils": "^4.0.4",
"csrf": "^3.1.0",
"helmet-csp": "^3.4.0"
},
"repository": {
"type": "git",
"url": "git+https://github.com/adonisjs/shield.git"
},
"bugs": {
"url": "https://github.com/adonisjs/shield/issues"
},
"homepage": "https://github.com/adonisjs/shield#readme",
"nyc": {
"exclude": [
"test"
],
"extension": [
".ts"
]
},
"husky": {
"hooks": {
"commit-msg": "node ./node_modules/@adonisjs/mrm-preset/validateCommit/conventional/validate.js"
}
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
},
"adonisjs": {
"instructionsMd": "./build/instructions.md",
"types": "@adonisjs/shield",
"providers": [
"@adonisjs/shield"
],
"templates": {
"config": [
"shield.txt"
]
}
},
"publishConfig": {
"tag": "latest",
"access": "public"
},
"np": {
"contents": ".",
"anyBranch": false
},
"mrmConfig": {
"core": true,
"license": "MIT",
"services": [
"github-actions"
],
"minNodeVersion": "14.15.4",
"probotApps": [
"stale",
"lock"
],
"runGhActionsOnWindows": true
},
"eslintConfig": {
"extends": [
"plugin:adonis/typescriptPackage",
"prettier"
],
"plugins": [
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
},
"eslintIgnore": [
"build"
],
"prettier": {
"trailingComma": "es5",
"semi": false,
"singleQuote": true,
"useTabs": false,
"quoteProps": "consistent",
"bracketSpacing": true,
"arrowParens": "always",
"printWidth": 100
}
}