auth revamp
This commit is contained in:
parent
14d8fd6280
commit
4719709602
|
@ -0,0 +1,2 @@
|
|||
|
||||
MONGODB_CONNECTION_STRING = mongodb+srv://admin:ABxXFUBs5FMiAaDJ@form.iynew.mongodb.net/<dbname>?retryWrites=true&w=majority
|
|
@ -3,8 +3,8 @@
|
|||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
/src/.env
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
const jwt = require("jsonwebtoken");
|
||||
|
||||
const auth = (req, res, next) => {
|
||||
try {
|
||||
const token = req.header("x-auth-token");
|
||||
if (!token)
|
||||
return res
|
||||
.status(401)
|
||||
.json({ msg: "No authentication token, authorization denied." });
|
||||
|
||||
const verified = jwt.verify(token, process.env.JWT_SECRET);
|
||||
if (!verified)
|
||||
return res
|
||||
.status(401)
|
||||
.json({ msg: "Token verification failed, authorization denied." });
|
||||
|
||||
req.user = verified.id;
|
||||
next();
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = auth;
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020 ealush
|
||||
|
||||
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.
|
|
@ -0,0 +1,101 @@
|
|||
# Context
|
||||
|
||||
Simple utility that creates a multi-layerd context singleton.
|
||||
It allows you to keep reference for shared variables, and access them later down in your function call even if not declared in the same scope.
|
||||
|
||||
It was built for [vest](https://github.com/ealush/vest) validations frameworks, but can be used in all sort of places.
|
||||
|
||||
```js
|
||||
// myContext.js
|
||||
import createContext from 'context';
|
||||
|
||||
export default createContext();
|
||||
```
|
||||
|
||||
```js
|
||||
// framework.js
|
||||
|
||||
import context from './myContext.js';
|
||||
|
||||
function suite(id, tests) {
|
||||
context.run({ suiteId: id }, () => tests());
|
||||
// ...
|
||||
}
|
||||
|
||||
function group(name, groupTests) {
|
||||
const { suiteId } = context.use();
|
||||
|
||||
context.run(
|
||||
{
|
||||
group: name,
|
||||
},
|
||||
() => groupTests()
|
||||
);
|
||||
}
|
||||
|
||||
function test(message, cb) {
|
||||
const { suiteId, group } = context.use();
|
||||
|
||||
const testId = Math.random(); // 0.8418151199238901
|
||||
|
||||
const testData = context.run({ test: testId }, () => cb());
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
export { suite, group, test } from './framework';
|
||||
```
|
||||
|
||||
```js
|
||||
import testFramework from './framwork.js';
|
||||
|
||||
suite('some_id', () => {
|
||||
/*
|
||||
context now is:
|
||||
{
|
||||
suiteId: 'some_id'
|
||||
}
|
||||
*/
|
||||
|
||||
group('some_group_name', () => {
|
||||
/*
|
||||
context now is:
|
||||
{
|
||||
group: 'some_group_name',
|
||||
parentContext: {
|
||||
suiteId: 'some_id',
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
test('blah blah', () => {
|
||||
/*
|
||||
context now is:
|
||||
{
|
||||
test: 0.8418151199238901,
|
||||
parentContext: {
|
||||
group: 'some_group_name',
|
||||
parentContext: {
|
||||
suiteId: 'some_id',
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Binding a function with context
|
||||
|
||||
You can bind a function to a context with ctx.bind, this allows you to create a bound function that's when called - will be called with that bound context, even if not in the same scope anymore.
|
||||
|
||||
```js
|
||||
const boundFunction = ctx.bind(ctxRef, fn, ...args);
|
||||
|
||||
boundFunction() // Will run with the context as if you run it directly within ctx.run();
|
||||
```
|
||||
|
||||
## Context initialization
|
||||
|
||||
You can add an init function to your context creation. The init function will run every time you call context.run, to allow you to set in-flight keys to your context. It accepts two params - the provided ctxRef, and the parent context when nested.
|
|
@ -0,0 +1,180 @@
|
|||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
function _defineProperties(target, props) {
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var descriptor = props[i];
|
||||
descriptor.enumerable = descriptor.enumerable || false;
|
||||
descriptor.configurable = true;
|
||||
if ("value" in descriptor) descriptor.writable = true;
|
||||
Object.defineProperty(target, descriptor.key, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) {
|
||||
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
||||
if (staticProps) _defineProperties(Constructor, staticProps);
|
||||
return Constructor;
|
||||
}
|
||||
|
||||
var getInnerName = function getInnerName(name) {
|
||||
return "__" + name;
|
||||
};
|
||||
|
||||
var Context = /*#__PURE__*/function () {
|
||||
function Context(_ref, ctxRef) {
|
||||
var _init;
|
||||
|
||||
var use = _ref.use,
|
||||
set = _ref.set,
|
||||
addQueryableProperties = _ref.addQueryableProperties,
|
||||
init = _ref.init;
|
||||
this._parentContext = null;
|
||||
var ctx = use();
|
||||
var usedRef = typeof init === 'function' ? (_init = init(ctxRef, ctx)) !== null && _init !== void 0 ? _init : ctxRef : ctxRef;
|
||||
var queryableProperties = addQueryableProperties(usedRef);
|
||||
|
||||
if (usedRef && typeof usedRef === 'object') {
|
||||
for (var key in queryableProperties) {
|
||||
if (Object.prototype.hasOwnProperty.call(usedRef, key)) {
|
||||
this[getInnerName(key)] = usedRef[key];
|
||||
}
|
||||
|
||||
this.addLookupProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx) {
|
||||
this.setParentContext(ctx);
|
||||
}
|
||||
|
||||
set(this);
|
||||
}
|
||||
|
||||
Context.is = function is(value) {
|
||||
return value instanceof Context;
|
||||
};
|
||||
|
||||
var _proto = Context.prototype;
|
||||
|
||||
_proto.addLookupProperty = function addLookupProperty(key) {
|
||||
var innerName = getInnerName(key);
|
||||
Object.defineProperty(this, key, {
|
||||
get: function get() {
|
||||
return this.lookup(innerName);
|
||||
},
|
||||
set: function set(value) {
|
||||
throw new Error("Context: Unable to set \"" + key + "\" to `" + JSON.stringify(value) + "`. Context properties cannot be set directly. Use context.run() instead.");
|
||||
}
|
||||
});
|
||||
} // @ts-ignore - we actually do use lookup
|
||||
;
|
||||
|
||||
_proto.lookup = function lookup(key) {
|
||||
var ctx = this;
|
||||
|
||||
do {
|
||||
if (ctx.hasOwnProperty(key)) {
|
||||
return ctx[key];
|
||||
}
|
||||
|
||||
if (Context.is(ctx.parentContext)) {
|
||||
ctx = ctx.parentContext;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} while (ctx);
|
||||
};
|
||||
|
||||
_proto.setParentContext = function setParentContext(parentContext) {
|
||||
if (Context.is(this)) {
|
||||
this._parentContext = parentContext;
|
||||
}
|
||||
};
|
||||
|
||||
_createClass(Context, [{
|
||||
key: "parentContext",
|
||||
get: function get() {
|
||||
return this._parentContext;
|
||||
}
|
||||
}]);
|
||||
|
||||
return Context;
|
||||
}();
|
||||
|
||||
function createContext(init) {
|
||||
var storage = {
|
||||
ctx: undefined
|
||||
};
|
||||
var queryableProperties = {};
|
||||
|
||||
function addQueryableProperties(ctxRef) {
|
||||
if (!ctxRef || typeof ctxRef !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (var key in ctxRef) {
|
||||
if (Object.prototype.hasOwnProperty.call(ctxRef, key)) {
|
||||
queryableProperties[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return queryableProperties;
|
||||
}
|
||||
|
||||
function use() {
|
||||
return storage.ctx;
|
||||
}
|
||||
|
||||
function set(value) {
|
||||
return storage.ctx = value;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
var ctx = use();
|
||||
|
||||
if (!Context.is(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(ctx.parentContext);
|
||||
}
|
||||
|
||||
function run(ctxRef, fn) {
|
||||
var ctx = new Context({
|
||||
set: set,
|
||||
use: use,
|
||||
addQueryableProperties: addQueryableProperties,
|
||||
init: init
|
||||
}, ctxRef);
|
||||
var res = fn(ctx);
|
||||
clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
function bind(ctxRef, fn) {
|
||||
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
||||
args[_key - 2] = arguments[_key];
|
||||
}
|
||||
|
||||
return function () {
|
||||
for (var _len2 = arguments.length, runTimeArgs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
||||
runTimeArgs[_key2] = arguments[_key2];
|
||||
}
|
||||
|
||||
return run(ctxRef, function () {
|
||||
return fn.apply(void 0, args.concat(runTimeArgs));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
use: use,
|
||||
run: run,
|
||||
bind: bind
|
||||
};
|
||||
}
|
||||
|
||||
exports.default = createContext;
|
||||
//# sourceMappingURL=context.cjs.development.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,2 @@
|
|||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var t=function(t){return"__"+t},e=function(){function e(e,n){var r,o=e.use,i=e.set,u=e.addQueryableProperties,a=e.init;this._parentContext=null;var c=o(),s="function"==typeof a&&null!==(r=a(n,c))&&void 0!==r?r:n,f=u(s);if(s&&"object"==typeof s)for(var p in f)Object.prototype.hasOwnProperty.call(s,p)&&(this[t(p)]=s[p]),this.addLookupProperty(p);c&&this.setParentContext(c),i(this)}e.is=function(t){return t instanceof e};var n,r=e.prototype;return r.addLookupProperty=function(e){var n=t(e);Object.defineProperty(this,e,{get:function(){return this.lookup(n)},set:function(t){throw new Error('Context: Unable to set "'+e+'" to `'+JSON.stringify(t)+"`. Context properties cannot be set directly. Use context.run() instead.")}})},r.lookup=function(t){var n=this;do{if(n.hasOwnProperty(t))return n[t];if(!e.is(n.parentContext))return;n=n.parentContext}while(n)},r.setParentContext=function(t){e.is(this)&&(this._parentContext=t)},(n=[{key:"parentContext",get:function(){return this._parentContext}}])&&function(t,e){for(var n=0;n<e.length;n++){var r=e[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(t,r.key,r)}}(e.prototype,n),e}();exports.default=function(t){var n={ctx:void 0},r={};function o(t){if(!t||"object"!=typeof t)return{};for(var e in t)Object.prototype.hasOwnProperty.call(t,e)&&(r[e]=!0);return r}function i(){return n.ctx}function u(t){return n.ctx=t}function a(n,r){var a,c=r(new e({set:u,use:i,addQueryableProperties:o,init:t},n));return a=i(),e.is(a)&&u(a.parentContext),c}return{use:i,run:a,bind:function(t,e){for(var n=arguments.length,r=new Array(n>2?n-2:0),o=2;o<n;o++)r[o-2]=arguments[o];return function(){for(var n=arguments.length,o=new Array(n),i=0;i<n;i++)o[i]=arguments[i];return a(t,(function(){return e.apply(void 0,r.concat(o))}))}}}};
|
||||
//# sourceMappingURL=context.cjs.production.min.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,176 @@
|
|||
function _defineProperties(target, props) {
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
var descriptor = props[i];
|
||||
descriptor.enumerable = descriptor.enumerable || false;
|
||||
descriptor.configurable = true;
|
||||
if ("value" in descriptor) descriptor.writable = true;
|
||||
Object.defineProperty(target, descriptor.key, descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
function _createClass(Constructor, protoProps, staticProps) {
|
||||
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
|
||||
if (staticProps) _defineProperties(Constructor, staticProps);
|
||||
return Constructor;
|
||||
}
|
||||
|
||||
var getInnerName = function getInnerName(name) {
|
||||
return "__" + name;
|
||||
};
|
||||
|
||||
var Context = /*#__PURE__*/function () {
|
||||
function Context(_ref, ctxRef) {
|
||||
var _init;
|
||||
|
||||
var use = _ref.use,
|
||||
set = _ref.set,
|
||||
addQueryableProperties = _ref.addQueryableProperties,
|
||||
init = _ref.init;
|
||||
this._parentContext = null;
|
||||
var ctx = use();
|
||||
var usedRef = typeof init === 'function' ? (_init = init(ctxRef, ctx)) !== null && _init !== void 0 ? _init : ctxRef : ctxRef;
|
||||
var queryableProperties = addQueryableProperties(usedRef);
|
||||
|
||||
if (usedRef && typeof usedRef === 'object') {
|
||||
for (var key in queryableProperties) {
|
||||
if (Object.prototype.hasOwnProperty.call(usedRef, key)) {
|
||||
this[getInnerName(key)] = usedRef[key];
|
||||
}
|
||||
|
||||
this.addLookupProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx) {
|
||||
this.setParentContext(ctx);
|
||||
}
|
||||
|
||||
set(this);
|
||||
}
|
||||
|
||||
Context.is = function is(value) {
|
||||
return value instanceof Context;
|
||||
};
|
||||
|
||||
var _proto = Context.prototype;
|
||||
|
||||
_proto.addLookupProperty = function addLookupProperty(key) {
|
||||
var innerName = getInnerName(key);
|
||||
Object.defineProperty(this, key, {
|
||||
get: function get() {
|
||||
return this.lookup(innerName);
|
||||
},
|
||||
set: function set(value) {
|
||||
throw new Error("Context: Unable to set \"" + key + "\" to `" + JSON.stringify(value) + "`. Context properties cannot be set directly. Use context.run() instead.");
|
||||
}
|
||||
});
|
||||
} // @ts-ignore - we actually do use lookup
|
||||
;
|
||||
|
||||
_proto.lookup = function lookup(key) {
|
||||
var ctx = this;
|
||||
|
||||
do {
|
||||
if (ctx.hasOwnProperty(key)) {
|
||||
return ctx[key];
|
||||
}
|
||||
|
||||
if (Context.is(ctx.parentContext)) {
|
||||
ctx = ctx.parentContext;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} while (ctx);
|
||||
};
|
||||
|
||||
_proto.setParentContext = function setParentContext(parentContext) {
|
||||
if (Context.is(this)) {
|
||||
this._parentContext = parentContext;
|
||||
}
|
||||
};
|
||||
|
||||
_createClass(Context, [{
|
||||
key: "parentContext",
|
||||
get: function get() {
|
||||
return this._parentContext;
|
||||
}
|
||||
}]);
|
||||
|
||||
return Context;
|
||||
}();
|
||||
|
||||
function createContext(init) {
|
||||
var storage = {
|
||||
ctx: undefined
|
||||
};
|
||||
var queryableProperties = {};
|
||||
|
||||
function addQueryableProperties(ctxRef) {
|
||||
if (!ctxRef || typeof ctxRef !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (var key in ctxRef) {
|
||||
if (Object.prototype.hasOwnProperty.call(ctxRef, key)) {
|
||||
queryableProperties[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return queryableProperties;
|
||||
}
|
||||
|
||||
function use() {
|
||||
return storage.ctx;
|
||||
}
|
||||
|
||||
function set(value) {
|
||||
return storage.ctx = value;
|
||||
}
|
||||
|
||||
function clear() {
|
||||
var ctx = use();
|
||||
|
||||
if (!Context.is(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(ctx.parentContext);
|
||||
}
|
||||
|
||||
function run(ctxRef, fn) {
|
||||
var ctx = new Context({
|
||||
set: set,
|
||||
use: use,
|
||||
addQueryableProperties: addQueryableProperties,
|
||||
init: init
|
||||
}, ctxRef);
|
||||
var res = fn(ctx);
|
||||
clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
function bind(ctxRef, fn) {
|
||||
for (var _len = arguments.length, args = new Array(_len > 2 ? _len - 2 : 0), _key = 2; _key < _len; _key++) {
|
||||
args[_key - 2] = arguments[_key];
|
||||
}
|
||||
|
||||
return function () {
|
||||
for (var _len2 = arguments.length, runTimeArgs = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
||||
runTimeArgs[_key2] = arguments[_key2];
|
||||
}
|
||||
|
||||
return run(ctxRef, function () {
|
||||
return fn.apply(void 0, args.concat(runTimeArgs));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
use: use,
|
||||
run: run,
|
||||
bind: bind
|
||||
};
|
||||
}
|
||||
|
||||
export default createContext;
|
||||
//# sourceMappingURL=context.esm.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,39 @@
|
|||
declare type TypeCTXRef = {
|
||||
[key: string]: any;
|
||||
};
|
||||
export interface ICTXFN {
|
||||
(context: Context): any;
|
||||
}
|
||||
interface Init {
|
||||
(ctxRef?: TypeCTXRef, parentContext?: Context | void): TypeCTXRef | null;
|
||||
}
|
||||
declare type ContextOptions = {
|
||||
use: () => Context | void;
|
||||
set: (value: any) => any;
|
||||
addQueryableProperties: (ctxRef: TypeCTXRef) => TQueryableProperties;
|
||||
init?: Init;
|
||||
};
|
||||
declare type TQueryableProperties = {
|
||||
[key: string]: true;
|
||||
};
|
||||
export declare type TCTX = {
|
||||
use: () => Context | void;
|
||||
run: (ctxRef: TypeCTXRef, fn: ICTXFN) => any;
|
||||
bind: (ctxRef: TypeCTXRef, fn: (...args: any[]) => any, ...args: any[]) => (...runTimeArgs: any[]) => any;
|
||||
};
|
||||
declare class Context {
|
||||
private _parentContext;
|
||||
[key: string]: any;
|
||||
static is(value: any): value is Context;
|
||||
constructor({ use, set, addQueryableProperties, init }: ContextOptions, ctxRef: TypeCTXRef);
|
||||
addLookupProperty(key: string): void;
|
||||
private lookup;
|
||||
private setParentContext;
|
||||
get parentContext(): Context | null;
|
||||
}
|
||||
declare function createContext(init?: Init): {
|
||||
use: () => Context | void;
|
||||
run: (ctxRef: TypeCTXRef, fn: ICTXFN) => any;
|
||||
bind: (ctxRef: TypeCTXRef, fn: (...args: any[]) => any, ...args: any[]) => (...runTimeArgs: any[]) => any;
|
||||
};
|
||||
export default createContext;
|
|
@ -0,0 +1,8 @@
|
|||
|
||||
'use strict'
|
||||
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
module.exports = require('./context.cjs.production.min.js')
|
||||
} else {
|
||||
module.exports = require('./context.cjs.development.js')
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"_from": "context",
|
||||
"_id": "context@1.1.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-nfNLy6MbBleZuK0vDwxUnYyu1McpjaZIHo7a3+yNoLWEJtnUjnB4z5xYZhg3XmVcCflh5U2FeaHbHUfCCLSeHA==",
|
||||
"_location": "/context",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "tag",
|
||||
"registry": true,
|
||||
"raw": "context",
|
||||
"name": "context",
|
||||
"escapedName": "context",
|
||||
"rawSpec": "",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "latest"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"#USER",
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/context/-/context-1.1.0.tgz",
|
||||
"_shasum": "1675cfe546b4d8f9925a2c4896a7ee41e917f015",
|
||||
"_spec": "context",
|
||||
"_where": "C:\\Priyathamwork\\locaft\\locaft\\auth",
|
||||
"author": {
|
||||
"name": "ealush"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/ealush/context/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"deprecated": false,
|
||||
"description": "Simple utility that creates a multi-layerd context singleton. It allows you to keep reference for shared variables, and access them later down in your function call even if not declared in the same scope.",
|
||||
"devDependencies": {
|
||||
"husky": "^4.2.5",
|
||||
"tsdx": "^0.13.2",
|
||||
"tslib": "^2.0.1",
|
||||
"typescript": "^4.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"homepage": "https://github.com/ealush/context#readme",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "tsdx lint"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/context.esm.js",
|
||||
"name": "context",
|
||||
"peerDependencies": {},
|
||||
"prettier": {
|
||||
"printWidth": 80,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "es5"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ealush/context.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsdx build",
|
||||
"lint": "tsdx lint",
|
||||
"prepare": "tsdx build",
|
||||
"start": "tsdx watch",
|
||||
"test": "tsdx test"
|
||||
},
|
||||
"typings": "dist/index.d.ts",
|
||||
"version": "1.1.0"
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
type TypeCTXRef = { [key: string]: any };
|
||||
|
||||
export interface ICTXFN {
|
||||
(context: Context): any;
|
||||
}
|
||||
interface Init {
|
||||
(ctxRef?: TypeCTXRef, parentContext?: Context | void): TypeCTXRef | null;
|
||||
}
|
||||
|
||||
type ContextOptions = {
|
||||
use: () => Context | void;
|
||||
set: (value: any) => any;
|
||||
addQueryableProperties: (ctxRef: TypeCTXRef) => TQueryableProperties;
|
||||
init?: Init;
|
||||
};
|
||||
|
||||
type TQueryableProperties = { [key: string]: true };
|
||||
|
||||
export type TCTX = {
|
||||
use: () => Context | void;
|
||||
run: (ctxRef: TypeCTXRef, fn: ICTXFN) => any;
|
||||
bind: (
|
||||
ctxRef: TypeCTXRef,
|
||||
fn: (...args: any[]) => any,
|
||||
...args: any[]
|
||||
) => (...runTimeArgs: any[]) => any;
|
||||
};
|
||||
|
||||
const getInnerName = (name: string): string => `__${name}`;
|
||||
|
||||
class Context {
|
||||
private _parentContext: Context | null = null;
|
||||
[key: string]: any;
|
||||
|
||||
static is(value: any): value is Context {
|
||||
return value instanceof Context;
|
||||
}
|
||||
|
||||
constructor(
|
||||
{ use, set, addQueryableProperties, init }: ContextOptions,
|
||||
ctxRef: TypeCTXRef
|
||||
) {
|
||||
const ctx = use();
|
||||
|
||||
const usedRef =
|
||||
typeof init === 'function' ? init(ctxRef, ctx) ?? ctxRef : ctxRef;
|
||||
|
||||
const queryableProperties = addQueryableProperties(usedRef);
|
||||
|
||||
if (usedRef && typeof usedRef === 'object') {
|
||||
for (const key in queryableProperties) {
|
||||
if (Object.prototype.hasOwnProperty.call(usedRef, key)) {
|
||||
this[getInnerName(key)] = usedRef[key];
|
||||
}
|
||||
this.addLookupProperty(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx) {
|
||||
this.setParentContext(ctx);
|
||||
}
|
||||
|
||||
set(this);
|
||||
}
|
||||
|
||||
addLookupProperty(key: string) {
|
||||
const innerName = getInnerName(key);
|
||||
|
||||
Object.defineProperty(this, key, {
|
||||
get() {
|
||||
return this.lookup(innerName);
|
||||
},
|
||||
set(value) {
|
||||
throw new Error(
|
||||
`Context: Unable to set "${key}" to \`${JSON.stringify(
|
||||
value
|
||||
)}\`. Context properties cannot be set directly. Use context.run() instead.`
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// @ts-ignore - we actually do use lookup
|
||||
private lookup(key: string) {
|
||||
let ctx: Context = this;
|
||||
do {
|
||||
if (ctx.hasOwnProperty(key)) {
|
||||
return ctx[key];
|
||||
}
|
||||
if (Context.is(ctx.parentContext)) {
|
||||
ctx = ctx.parentContext;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} while (ctx);
|
||||
}
|
||||
|
||||
private setParentContext(parentContext: Context) {
|
||||
if (Context.is(this)) {
|
||||
this._parentContext = parentContext;
|
||||
}
|
||||
}
|
||||
|
||||
get parentContext(): Context | null {
|
||||
return this._parentContext;
|
||||
}
|
||||
}
|
||||
|
||||
function createContext(init?: Init) {
|
||||
const storage = {
|
||||
ctx: undefined,
|
||||
};
|
||||
|
||||
const queryableProperties: TQueryableProperties = {};
|
||||
|
||||
function addQueryableProperties(ctxRef: TypeCTXRef): TQueryableProperties {
|
||||
if (!ctxRef || typeof ctxRef !== 'object') {
|
||||
return {};
|
||||
}
|
||||
|
||||
for (const key in ctxRef) {
|
||||
if (Object.prototype.hasOwnProperty.call(ctxRef, key)) {
|
||||
queryableProperties[key] = true;
|
||||
}
|
||||
}
|
||||
|
||||
return queryableProperties;
|
||||
}
|
||||
|
||||
function use(): Context | void {
|
||||
return storage.ctx;
|
||||
}
|
||||
function set(value: any) {
|
||||
return (storage.ctx = value);
|
||||
}
|
||||
function clear() {
|
||||
const ctx = use();
|
||||
|
||||
if (!Context.is(ctx)) {
|
||||
return;
|
||||
}
|
||||
|
||||
set(ctx.parentContext);
|
||||
}
|
||||
function run(ctxRef: TypeCTXRef, fn: ICTXFN) {
|
||||
const ctx = new Context({ set, use, addQueryableProperties, init }, ctxRef);
|
||||
|
||||
const res = fn(ctx);
|
||||
|
||||
clear();
|
||||
return res;
|
||||
}
|
||||
|
||||
function bind(
|
||||
ctxRef: TypeCTXRef,
|
||||
fn: (...args: any[]) => any,
|
||||
...args: any[]
|
||||
) {
|
||||
return function(...runTimeArgs: any[]) {
|
||||
return run(ctxRef, function() {
|
||||
return fn(...args, ...runTimeArgs);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
use,
|
||||
run,
|
||||
bind,
|
||||
};
|
||||
}
|
||||
|
||||
export default createContext;
|
|
@ -0,0 +1,33 @@
|
|||
# contributing to `cors`
|
||||
|
||||
CORS is a node.js package for providing a [connect](http://www.senchalabs.org/connect/)/[express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options. Learn more about the project in [the README](README.md).
|
||||
|
||||
## The CORS Spec
|
||||
|
||||
[http://www.w3.org/TR/cors/](http://www.w3.org/TR/cors/)
|
||||
|
||||
## Pull Requests Welcome
|
||||
|
||||
* Include `'use strict';` in every javascript file.
|
||||
* 2 space indentation.
|
||||
* Please run the testing steps below before submitting.
|
||||
|
||||
## Testing
|
||||
|
||||
```bash
|
||||
$ npm install
|
||||
$ npm test
|
||||
```
|
||||
|
||||
## Interactive Testing Harness
|
||||
|
||||
[http://node-cors-client.herokuapp.com](http://node-cors-client.herokuapp.com)
|
||||
|
||||
Related git repositories:
|
||||
|
||||
* [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
|
||||
* [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](http://www.opensource.org/licenses/mit-license.php)
|
|
@ -0,0 +1,58 @@
|
|||
2.8.5 / 2018-11-04
|
||||
==================
|
||||
|
||||
* Fix setting `maxAge` option to `0`
|
||||
|
||||
2.8.4 / 2017-07-12
|
||||
==================
|
||||
|
||||
* Work-around Safari bug in default pre-flight response
|
||||
|
||||
2.8.3 / 2017-03-29
|
||||
==================
|
||||
|
||||
* Fix error when options delegate missing `methods` option
|
||||
|
||||
2.8.2 / 2017-03-28
|
||||
==================
|
||||
|
||||
* Fix error when frozen options are passed
|
||||
* Send "Vary: Origin" when using regular expressions
|
||||
* Send "Vary: Access-Control-Request-Headers" when dynamic `allowedHeaders`
|
||||
|
||||
2.8.1 / 2016-09-08
|
||||
==================
|
||||
|
||||
This release only changed documentation.
|
||||
|
||||
2.8.0 / 2016-08-23
|
||||
==================
|
||||
|
||||
* Add `optionsSuccessStatus` option
|
||||
|
||||
2.7.2 / 2016-08-23
|
||||
==================
|
||||
|
||||
* Fix error when Node.js running in strict mode
|
||||
|
||||
2.7.1 / 2015-05-28
|
||||
==================
|
||||
|
||||
* Move module into expressjs organization
|
||||
|
||||
2.7.0 / 2015-05-28
|
||||
==================
|
||||
|
||||
* Allow array of matching condition as `origin` option
|
||||
* Allow regular expression as `origin` option
|
||||
|
||||
2.6.1 / 2015-05-28
|
||||
==================
|
||||
|
||||
* Update `license` in package.json
|
||||
|
||||
2.6.0 / 2015-04-27
|
||||
==================
|
||||
|
||||
* Add `preflightContinue` option
|
||||
* Fix "Vary: Origin" header added for "*"
|
|
@ -0,0 +1,22 @@
|
|||
(The MIT License)
|
||||
|
||||
Copyright (c) 2013 Troy Goode <troygoode@gmail.com>
|
||||
|
||||
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.
|
|
@ -0,0 +1,243 @@
|
|||
# cors
|
||||
|
||||
[![NPM Version][npm-image]][npm-url]
|
||||
[![NPM Downloads][downloads-image]][downloads-url]
|
||||
[![Build Status][travis-image]][travis-url]
|
||||
[![Test Coverage][coveralls-image]][coveralls-url]
|
||||
|
||||
CORS is a node.js package for providing a [Connect](http://www.senchalabs.org/connect/)/[Express](http://expressjs.com/) middleware that can be used to enable [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) with various options.
|
||||
|
||||
**[Follow me (@troygoode) on Twitter!](https://twitter.com/intent/user?screen_name=troygoode)**
|
||||
|
||||
* [Installation](#installation)
|
||||
* [Usage](#usage)
|
||||
* [Simple Usage](#simple-usage-enable-all-cors-requests)
|
||||
* [Enable CORS for a Single Route](#enable-cors-for-a-single-route)
|
||||
* [Configuring CORS](#configuring-cors)
|
||||
* [Configuring CORS Asynchronously](#configuring-cors-asynchronously)
|
||||
* [Enabling CORS Pre-Flight](#enabling-cors-pre-flight)
|
||||
* [Configuration Options](#configuration-options)
|
||||
* [Demo](#demo)
|
||||
* [License](#license)
|
||||
* [Author](#author)
|
||||
|
||||
## Installation
|
||||
|
||||
This is a [Node.js](https://nodejs.org/en/) module available through the
|
||||
[npm registry](https://www.npmjs.com/). Installation is done using the
|
||||
[`npm install` command](https://docs.npmjs.com/getting-started/installing-npm-packages-locally):
|
||||
|
||||
```sh
|
||||
$ npm install cors
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Simple Usage (Enable *All* CORS Requests)
|
||||
|
||||
```javascript
|
||||
var express = require('express')
|
||||
var cors = require('cors')
|
||||
var app = express()
|
||||
|
||||
app.use(cors())
|
||||
|
||||
app.get('/products/:id', function (req, res, next) {
|
||||
res.json({msg: 'This is CORS-enabled for all origins!'})
|
||||
})
|
||||
|
||||
app.listen(80, function () {
|
||||
console.log('CORS-enabled web server listening on port 80')
|
||||
})
|
||||
```
|
||||
|
||||
### Enable CORS for a Single Route
|
||||
|
||||
```javascript
|
||||
var express = require('express')
|
||||
var cors = require('cors')
|
||||
var app = express()
|
||||
|
||||
app.get('/products/:id', cors(), function (req, res, next) {
|
||||
res.json({msg: 'This is CORS-enabled for a Single Route'})
|
||||
})
|
||||
|
||||
app.listen(80, function () {
|
||||
console.log('CORS-enabled web server listening on port 80')
|
||||
})
|
||||
```
|
||||
|
||||
### Configuring CORS
|
||||
|
||||
```javascript
|
||||
var express = require('express')
|
||||
var cors = require('cors')
|
||||
var app = express()
|
||||
|
||||
var corsOptions = {
|
||||
origin: 'http://example.com',
|
||||
optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
|
||||
}
|
||||
|
||||
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
|
||||
res.json({msg: 'This is CORS-enabled for only example.com.'})
|
||||
})
|
||||
|
||||
app.listen(80, function () {
|
||||
console.log('CORS-enabled web server listening on port 80')
|
||||
})
|
||||
```
|
||||
|
||||
### Configuring CORS w/ Dynamic Origin
|
||||
|
||||
```javascript
|
||||
var express = require('express')
|
||||
var cors = require('cors')
|
||||
var app = express()
|
||||
|
||||
var whitelist = ['http://example1.com', 'http://example2.com']
|
||||
var corsOptions = {
|
||||
origin: function (origin, callback) {
|
||||
if (whitelist.indexOf(origin) !== -1) {
|
||||
callback(null, true)
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
app.get('/products/:id', cors(corsOptions), function (req, res, next) {
|
||||
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
|
||||
})
|
||||
|
||||
app.listen(80, function () {
|
||||
console.log('CORS-enabled web server listening on port 80')
|
||||
})
|
||||
```
|
||||
|
||||
If you do not want to block REST tools or server-to-server requests,
|
||||
add a `!origin` check in the origin function like so:
|
||||
|
||||
```javascript
|
||||
var corsOptions = {
|
||||
origin: function (origin, callback) {
|
||||
if (whitelist.indexOf(origin) !== -1 || !origin) {
|
||||
callback(null, true)
|
||||
} else {
|
||||
callback(new Error('Not allowed by CORS'))
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Enabling CORS Pre-Flight
|
||||
|
||||
Certain CORS requests are considered 'complex' and require an initial
|
||||
`OPTIONS` request (called the "pre-flight request"). An example of a
|
||||
'complex' CORS request is one that uses an HTTP verb other than
|
||||
GET/HEAD/POST (such as DELETE) or that uses custom headers. To enable
|
||||
pre-flighting, you must add a new OPTIONS handler for the route you want
|
||||
to support:
|
||||
|
||||
```javascript
|
||||
var express = require('express')
|
||||
var cors = require('cors')
|
||||
var app = express()
|
||||
|
||||
app.options('/products/:id', cors()) // enable pre-flight request for DELETE request
|
||||
app.del('/products/:id', cors(), function (req, res, next) {
|
||||
res.json({msg: 'This is CORS-enabled for all origins!'})
|
||||
})
|
||||
|
||||
app.listen(80, function () {
|
||||
console.log('CORS-enabled web server listening on port 80')
|
||||
})
|
||||
```
|
||||
|
||||
You can also enable pre-flight across-the-board like so:
|
||||
|
||||
```javascript
|
||||
app.options('*', cors()) // include before other routes
|
||||
```
|
||||
|
||||
### Configuring CORS Asynchronously
|
||||
|
||||
```javascript
|
||||
var express = require('express')
|
||||
var cors = require('cors')
|
||||
var app = express()
|
||||
|
||||
var whitelist = ['http://example1.com', 'http://example2.com']
|
||||
var corsOptionsDelegate = function (req, callback) {
|
||||
var corsOptions;
|
||||
if (whitelist.indexOf(req.header('Origin')) !== -1) {
|
||||
corsOptions = { origin: true } // reflect (enable) the requested origin in the CORS response
|
||||
} else {
|
||||
corsOptions = { origin: false } // disable CORS for this request
|
||||
}
|
||||
callback(null, corsOptions) // callback expects two parameters: error and options
|
||||
}
|
||||
|
||||
app.get('/products/:id', cors(corsOptionsDelegate), function (req, res, next) {
|
||||
res.json({msg: 'This is CORS-enabled for a whitelisted domain.'})
|
||||
})
|
||||
|
||||
app.listen(80, function () {
|
||||
console.log('CORS-enabled web server listening on port 80')
|
||||
})
|
||||
```
|
||||
|
||||
## Configuration Options
|
||||
|
||||
* `origin`: Configures the **Access-Control-Allow-Origin** CORS header. Possible values:
|
||||
- `Boolean` - set `origin` to `true` to reflect the [request origin](http://tools.ietf.org/html/draft-abarth-origin-09), as defined by `req.header('Origin')`, or set it to `false` to disable CORS.
|
||||
- `String` - set `origin` to a specific origin. For example if you set it to `"http://example.com"` only requests from "http://example.com" will be allowed.
|
||||
- `RegExp` - set `origin` to a regular expression pattern which will be used to test the request origin. If it's a match, the request origin will be reflected. For example the pattern `/example\.com$/` will reflect any request that is coming from an origin ending with "example.com".
|
||||
- `Array` - set `origin` to an array of valid origins. Each origin can be a `String` or a `RegExp`. For example `["http://example1.com", /\.example2\.com$/]` will accept any request from "http://example1.com" or from a subdomain of "example2.com".
|
||||
- `Function` - set `origin` to a function implementing some custom logic. The function takes the request origin as the first parameter and a callback (which expects the signature `err [object], allow [bool]`) as the second.
|
||||
* `methods`: Configures the **Access-Control-Allow-Methods** CORS header. Expects a comma-delimited string (ex: 'GET,PUT,POST') or an array (ex: `['GET', 'PUT', 'POST']`).
|
||||
* `allowedHeaders`: Configures the **Access-Control-Allow-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Type,Authorization') or an array (ex: `['Content-Type', 'Authorization']`). If not specified, defaults to reflecting the headers specified in the request's **Access-Control-Request-Headers** header.
|
||||
* `exposedHeaders`: Configures the **Access-Control-Expose-Headers** CORS header. Expects a comma-delimited string (ex: 'Content-Range,X-Content-Range') or an array (ex: `['Content-Range', 'X-Content-Range']`). If not specified, no custom headers are exposed.
|
||||
* `credentials`: Configures the **Access-Control-Allow-Credentials** CORS header. Set to `true` to pass the header, otherwise it is omitted.
|
||||
* `maxAge`: Configures the **Access-Control-Max-Age** CORS header. Set to an integer to pass the header, otherwise it is omitted.
|
||||
* `preflightContinue`: Pass the CORS preflight response to the next handler.
|
||||
* `optionsSuccessStatus`: Provides a status code to use for successful `OPTIONS` requests, since some legacy browsers (IE11, various SmartTVs) choke on `204`.
|
||||
|
||||
The default configuration is the equivalent of:
|
||||
|
||||
```json
|
||||
{
|
||||
"origin": "*",
|
||||
"methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
|
||||
"preflightContinue": false,
|
||||
"optionsSuccessStatus": 204
|
||||
}
|
||||
```
|
||||
|
||||
For details on the effect of each CORS header, read [this](http://www.html5rocks.com/en/tutorials/cors/) article on HTML5 Rocks.
|
||||
|
||||
## Demo
|
||||
|
||||
A demo that illustrates CORS working (and not working) using jQuery is available here: [http://node-cors-client.herokuapp.com/](http://node-cors-client.herokuapp.com/)
|
||||
|
||||
Code for that demo can be found here:
|
||||
|
||||
* Client: [https://github.com/TroyGoode/node-cors-client](https://github.com/TroyGoode/node-cors-client)
|
||||
* Server: [https://github.com/TroyGoode/node-cors-server](https://github.com/TroyGoode/node-cors-server)
|
||||
|
||||
## License
|
||||
|
||||
[MIT License](http://www.opensource.org/licenses/mit-license.php)
|
||||
|
||||
## Author
|
||||
|
||||
[Troy Goode](https://github.com/TroyGoode) ([troygoode@gmail.com](mailto:troygoode@gmail.com))
|
||||
|
||||
[coveralls-image]: https://img.shields.io/coveralls/expressjs/cors/master.svg
|
||||
[coveralls-url]: https://coveralls.io/r/expressjs/cors?branch=master
|
||||
[downloads-image]: https://img.shields.io/npm/dm/cors.svg
|
||||
[downloads-url]: https://npmjs.org/package/cors
|
||||
[npm-image]: https://img.shields.io/npm/v/cors.svg
|
||||
[npm-url]: https://npmjs.org/package/cors
|
||||
[travis-image]: https://img.shields.io/travis/expressjs/cors/master.svg
|
||||
[travis-url]: https://travis-ci.org/expressjs/cors
|
|
@ -0,0 +1,238 @@
|
|||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
var assign = require('object-assign');
|
||||
var vary = require('vary');
|
||||
|
||||
var defaults = {
|
||||
origin: '*',
|
||||
methods: 'GET,HEAD,PUT,PATCH,POST,DELETE',
|
||||
preflightContinue: false,
|
||||
optionsSuccessStatus: 204
|
||||
};
|
||||
|
||||
function isString(s) {
|
||||
return typeof s === 'string' || s instanceof String;
|
||||
}
|
||||
|
||||
function isOriginAllowed(origin, allowedOrigin) {
|
||||
if (Array.isArray(allowedOrigin)) {
|
||||
for (var i = 0; i < allowedOrigin.length; ++i) {
|
||||
if (isOriginAllowed(origin, allowedOrigin[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
} else if (isString(allowedOrigin)) {
|
||||
return origin === allowedOrigin;
|
||||
} else if (allowedOrigin instanceof RegExp) {
|
||||
return allowedOrigin.test(origin);
|
||||
} else {
|
||||
return !!allowedOrigin;
|
||||
}
|
||||
}
|
||||
|
||||
function configureOrigin(options, req) {
|
||||
var requestOrigin = req.headers.origin,
|
||||
headers = [],
|
||||
isAllowed;
|
||||
|
||||
if (!options.origin || options.origin === '*') {
|
||||
// allow any origin
|
||||
headers.push([{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: '*'
|
||||
}]);
|
||||
} else if (isString(options.origin)) {
|
||||
// fixed origin
|
||||
headers.push([{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: options.origin
|
||||
}]);
|
||||
headers.push([{
|
||||
key: 'Vary',
|
||||
value: 'Origin'
|
||||
}]);
|
||||
} else {
|
||||
isAllowed = isOriginAllowed(requestOrigin, options.origin);
|
||||
// reflect origin
|
||||
headers.push([{
|
||||
key: 'Access-Control-Allow-Origin',
|
||||
value: isAllowed ? requestOrigin : false
|
||||
}]);
|
||||
headers.push([{
|
||||
key: 'Vary',
|
||||
value: 'Origin'
|
||||
}]);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
function configureMethods(options) {
|
||||
var methods = options.methods;
|
||||
if (methods.join) {
|
||||
methods = options.methods.join(','); // .methods is an array, so turn it into a string
|
||||
}
|
||||
return {
|
||||
key: 'Access-Control-Allow-Methods',
|
||||
value: methods
|
||||
};
|
||||
}
|
||||
|
||||
function configureCredentials(options) {
|
||||
if (options.credentials === true) {
|
||||
return {
|
||||
key: 'Access-Control-Allow-Credentials',
|
||||
value: 'true'
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function configureAllowedHeaders(options, req) {
|
||||
var allowedHeaders = options.allowedHeaders || options.headers;
|
||||
var headers = [];
|
||||
|
||||
if (!allowedHeaders) {
|
||||
allowedHeaders = req.headers['access-control-request-headers']; // .headers wasn't specified, so reflect the request headers
|
||||
headers.push([{
|
||||
key: 'Vary',
|
||||
value: 'Access-Control-Request-Headers'
|
||||
}]);
|
||||
} else if (allowedHeaders.join) {
|
||||
allowedHeaders = allowedHeaders.join(','); // .headers is an array, so turn it into a string
|
||||
}
|
||||
if (allowedHeaders && allowedHeaders.length) {
|
||||
headers.push([{
|
||||
key: 'Access-Control-Allow-Headers',
|
||||
value: allowedHeaders
|
||||
}]);
|
||||
}
|
||||
|
||||
return headers;
|
||||
}
|
||||
|
||||
function configureExposedHeaders(options) {
|
||||
var headers = options.exposedHeaders;
|
||||
if (!headers) {
|
||||
return null;
|
||||
} else if (headers.join) {
|
||||
headers = headers.join(','); // .headers is an array, so turn it into a string
|
||||
}
|
||||
if (headers && headers.length) {
|
||||
return {
|
||||
key: 'Access-Control-Expose-Headers',
|
||||
value: headers
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function configureMaxAge(options) {
|
||||
var maxAge = (typeof options.maxAge === 'number' || options.maxAge) && options.maxAge.toString()
|
||||
if (maxAge && maxAge.length) {
|
||||
return {
|
||||
key: 'Access-Control-Max-Age',
|
||||
value: maxAge
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function applyHeaders(headers, res) {
|
||||
for (var i = 0, n = headers.length; i < n; i++) {
|
||||
var header = headers[i];
|
||||
if (header) {
|
||||
if (Array.isArray(header)) {
|
||||
applyHeaders(header, res);
|
||||
} else if (header.key === 'Vary' && header.value) {
|
||||
vary(res, header.value);
|
||||
} else if (header.value) {
|
||||
res.setHeader(header.key, header.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cors(options, req, res, next) {
|
||||
var headers = [],
|
||||
method = req.method && req.method.toUpperCase && req.method.toUpperCase();
|
||||
|
||||
if (method === 'OPTIONS') {
|
||||
// preflight
|
||||
headers.push(configureOrigin(options, req));
|
||||
headers.push(configureCredentials(options, req));
|
||||
headers.push(configureMethods(options, req));
|
||||
headers.push(configureAllowedHeaders(options, req));
|
||||
headers.push(configureMaxAge(options, req));
|
||||
headers.push(configureExposedHeaders(options, req));
|
||||
applyHeaders(headers, res);
|
||||
|
||||
if (options.preflightContinue) {
|
||||
next();
|
||||
} else {
|
||||
// Safari (and potentially other browsers) need content-length 0,
|
||||
// for 204 or they just hang waiting for a body
|
||||
res.statusCode = options.optionsSuccessStatus;
|
||||
res.setHeader('Content-Length', '0');
|
||||
res.end();
|
||||
}
|
||||
} else {
|
||||
// actual response
|
||||
headers.push(configureOrigin(options, req));
|
||||
headers.push(configureCredentials(options, req));
|
||||
headers.push(configureExposedHeaders(options, req));
|
||||
applyHeaders(headers, res);
|
||||
next();
|
||||
}
|
||||
}
|
||||
|
||||
function middlewareWrapper(o) {
|
||||
// if options are static (either via defaults or custom options passed in), wrap in a function
|
||||
var optionsCallback = null;
|
||||
if (typeof o === 'function') {
|
||||
optionsCallback = o;
|
||||
} else {
|
||||
optionsCallback = function (req, cb) {
|
||||
cb(null, o);
|
||||
};
|
||||
}
|
||||
|
||||
return function corsMiddleware(req, res, next) {
|
||||
optionsCallback(req, function (err, options) {
|
||||
if (err) {
|
||||
next(err);
|
||||
} else {
|
||||
var corsOptions = assign({}, defaults, options);
|
||||
var originCallback = null;
|
||||
if (corsOptions.origin && typeof corsOptions.origin === 'function') {
|
||||
originCallback = corsOptions.origin;
|
||||
} else if (corsOptions.origin) {
|
||||
originCallback = function (origin, cb) {
|
||||
cb(null, corsOptions.origin);
|
||||
};
|
||||
}
|
||||
|
||||
if (originCallback) {
|
||||
originCallback(req.headers.origin, function (err2, origin) {
|
||||
if (err2 || !origin) {
|
||||
next(err2);
|
||||
} else {
|
||||
corsOptions.origin = origin;
|
||||
cors(corsOptions, req, res, next);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
next();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// can pass either an options hash, an options delegate, or nothing
|
||||
module.exports = middlewareWrapper;
|
||||
|
||||
}());
|
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"_from": "cors",
|
||||
"_id": "cors@2.8.5",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"_location": "/cors",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "tag",
|
||||
"registry": true,
|
||||
"raw": "cors",
|
||||
"name": "cors",
|
||||
"escapedName": "cors",
|
||||
"rawSpec": "",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "latest"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"#USER",
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"_shasum": "eac11da51592dd86b9f06f6e7ac293b3df875d29",
|
||||
"_spec": "cors",
|
||||
"_where": "C:\\Priyathamwork\\locaft\\locaft\\auth",
|
||||
"author": {
|
||||
"name": "Troy Goode",
|
||||
"email": "troygoode@gmail.com",
|
||||
"url": "https://github.com/troygoode/"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/expressjs/cors/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"deprecated": false,
|
||||
"description": "Node.js CORS middleware",
|
||||
"devDependencies": {
|
||||
"after": "0.8.2",
|
||||
"eslint": "2.13.1",
|
||||
"express": "4.16.3",
|
||||
"mocha": "5.2.0",
|
||||
"nyc": "13.1.0",
|
||||
"supertest": "3.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"CONTRIBUTING.md",
|
||||
"HISTORY.md",
|
||||
"LICENSE",
|
||||
"README.md"
|
||||
],
|
||||
"homepage": "https://github.com/expressjs/cors#readme",
|
||||
"keywords": [
|
||||
"cors",
|
||||
"express",
|
||||
"connect",
|
||||
"middleware"
|
||||
],
|
||||
"license": "MIT",
|
||||
"main": "./lib/index.js",
|
||||
"name": "cors",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/expressjs/cors.git"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint lib test",
|
||||
"test": "npm run lint && nyc --reporter=html --reporter=text mocha --require test/support/env"
|
||||
},
|
||||
"version": "2.8.5"
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
||||
|
||||
## [8.2.0](https://github.com/motdotla/dotenv/compare/v8.1.0...v8.2.0) (2019-10-16)
|
||||
|
||||
## [8.1.0](https://github.com/motdotla/dotenv/compare/v7.0.0...v8.1.0) (2019-08-18)
|
||||
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* dropping Node v6 support because end-of-life
|
||||
|
||||
* Drop support for Node v6 (#392) ([2e9636a](https://github.com/motdotla/dotenv/commit/2e9636a)), closes [#392](https://github.com/motdotla/dotenv/issues/392)
|
||||
|
||||
# [8.0.0](https://github.com/motdotla/dotenv/compare/v7.0.0...v8.0.0) (2019-05-02)
|
||||
|
||||
- Drop support for Node v6 (#392) ([2e9636a](https://github.com/motdotla/dotenv/commit/2e9636a)), closes [#392](https://github.com/motdotla/dotenv/issues/392)
|
||||
|
||||
### BREAKING CHANGES
|
||||
|
||||
- dropping Node v6 support because end-of-life
|
||||
|
||||
## [7.0.0] - 2019-03-12
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fix removing unbalanced quotes ([#376](https://github.com/motdotla/dotenv/pull/376))
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed `load` alias for `config` for consistency throughout code and documentation.
|
||||
|
||||
## [6.2.0] - 2018-12-03
|
||||
|
||||
### Added
|
||||
|
||||
- Support preload configuration via environment variables ([#351](https://github.com/motdotla/dotenv/issues/351))
|
||||
|
||||
## [6.1.0] - 2018-10-08
|
||||
|
||||
### Added
|
||||
|
||||
- `debug` option for `config` and `parse` methods will turn on logging
|
||||
|
||||
## [6.0.0] - 2018-06-02
|
||||
|
||||
### Changed
|
||||
|
||||
- _Breaking:_ drop support for Node v4 ([#304](https://github.com/motdotla/dotenv/pull/304))
|
||||
|
||||
## [5.0.0] - 2018-01-29
|
||||
|
||||
### Added
|
||||
|
||||
- Testing against Node v8 and v9
|
||||
- Documentation on trim behavior of values
|
||||
- Documentation on how to use with `import`
|
||||
|
||||
### Changed
|
||||
|
||||
- _Breaking_: default `path` is now `path.resolve(process.cwd(), '.env')`
|
||||
- _Breaking_: does not write over keys already in `process.env` if the key has a falsy value
|
||||
- using `const` and `let` instead of `var`
|
||||
|
||||
### Removed
|
||||
|
||||
- Testing against Node v7
|
||||
|
||||
## [4.0.0] - 2016-12-23
|
||||
|
||||
### Changed
|
||||
|
||||
- Return Object with parsed content or error instead of false ([#165](https://github.com/motdotla/dotenv/pull/165)).
|
||||
|
||||
### Removed
|
||||
|
||||
- `verbose` option removed in favor of returning result.
|
||||
|
||||
## [3.0.0] - 2016-12-20
|
||||
|
||||
### Added
|
||||
|
||||
- `verbose` option will log any error messages. Off by default.
|
||||
- parses email addresses correctly
|
||||
- allow importing config method directly in ES6
|
||||
|
||||
### Changed
|
||||
|
||||
- Suppress error messages by default ([#154](https://github.com/motdotla/dotenv/pull/154))
|
||||
- Ignoring more files for NPM to make package download smaller
|
||||
|
||||
### Fixed
|
||||
|
||||
- False positive test due to case-sensitive variable ([#124](https://github.com/motdotla/dotenv/pull/124))
|
||||
|
||||
### Removed
|
||||
|
||||
- `silent` option removed in favor of `verbose`
|
||||
|
||||
## [2.0.0] - 2016-01-20
|
||||
|
||||
### Added
|
||||
|
||||
- CHANGELOG to ["make it easier for users and contributors to see precisely what notable changes have been made between each release"](http://keepachangelog.com/). Linked to from README
|
||||
- LICENSE to be more explicit about what was defined in `package.json`. Linked to from README
|
||||
- Testing nodejs v4 on travis-ci
|
||||
- added examples of how to use dotenv in different ways
|
||||
- return parsed object on success rather than boolean true
|
||||
|
||||
### Changed
|
||||
|
||||
- README has shorter description not referencing ruby gem since we don't have or want feature parity
|
||||
|
||||
### Removed
|
||||
|
||||
- Variable expansion and escaping so environment variables are encouraged to be fully orthogonal
|
||||
|
||||
## [1.2.0] - 2015-06-20
|
||||
|
||||
### Added
|
||||
|
||||
- Preload hook to require dotenv without including it in your code
|
||||
|
||||
### Changed
|
||||
|
||||
- clarified license to be "BSD-2-Clause" in `package.json`
|
||||
|
||||
### Fixed
|
||||
|
||||
- retain spaces in string vars
|
||||
|
||||
## [1.1.0] - 2015-03-31
|
||||
|
||||
### Added
|
||||
|
||||
- Silent option to silence `console.log` when `.env` missing
|
||||
|
||||
## [1.0.0] - 2015-03-13
|
||||
|
||||
### Removed
|
||||
|
||||
- support for multiple `.env` files. should always use one `.env` file for the current environment
|
||||
|
||||
[7.0.0]: https://github.com/motdotla/dotenv/compare/v6.2.0...v7.0.0
|
||||
[6.2.0]: https://github.com/motdotla/dotenv/compare/v6.1.0...v6.2.0
|
||||
[6.1.0]: https://github.com/motdotla/dotenv/compare/v6.0.0...v6.1.0
|
||||
[6.0.0]: https://github.com/motdotla/dotenv/compare/v5.0.0...v6.0.0
|
||||
[5.0.0]: https://github.com/motdotla/dotenv/compare/v4.0.0...v5.0.0
|
||||
[4.0.0]: https://github.com/motdotla/dotenv/compare/v3.0.0...v4.0.0
|
||||
[3.0.0]: https://github.com/motdotla/dotenv/compare/v2.0.0...v3.0.0
|
||||
[2.0.0]: https://github.com/motdotla/dotenv/compare/v1.2.0...v2.0.0
|
||||
[1.2.0]: https://github.com/motdotla/dotenv/compare/v1.1.0...v1.2.0
|
||||
[1.1.0]: https://github.com/motdotla/dotenv/compare/v1.0.0...v1.1.0
|
||||
[1.0.0]: https://github.com/motdotla/dotenv/compare/v0.4.0...v1.0.0
|
|
@ -0,0 +1,23 @@
|
|||
Copyright (c) 2015, Scott Motte
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,271 @@
|
|||
# dotenv
|
||||
|
||||
<img src="https://raw.githubusercontent.com/motdotla/dotenv/master/dotenv.png" alt="dotenv" align="right" />
|
||||
|
||||
Dotenv is a zero-dependency module that loads environment variables from a `.env` file into [`process.env`](https://nodejs.org/docs/latest/api/process.html#process_process_env). Storing configuration in the environment separate from code is based on [The Twelve-Factor App](http://12factor.net/config) methodology.
|
||||
|
||||
[](https://travis-ci.org/motdotla/dotenv)
|
||||
[](https://ci.appveyor.com/project/motdotla/dotenv/branch/master)
|
||||
[](https://www.npmjs.com/package/dotenv)
|
||||
[](https://github.com/feross/standard)
|
||||
[](https://coveralls.io/github/motdotla/dotenv?branch=coverall-intergration)
|
||||
[](LICENSE)
|
||||
[](https://conventionalcommits.org)
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
# with npm
|
||||
npm install dotenv
|
||||
|
||||
# or with Yarn
|
||||
yarn add dotenv
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
As early as possible in your application, require and configure dotenv.
|
||||
|
||||
```javascript
|
||||
require('dotenv').config()
|
||||
```
|
||||
|
||||
Create a `.env` file in the root directory of your project. Add
|
||||
environment-specific variables on new lines in the form of `NAME=VALUE`.
|
||||
For example:
|
||||
|
||||
```dosini
|
||||
DB_HOST=localhost
|
||||
DB_USER=root
|
||||
DB_PASS=s1mpl3
|
||||
```
|
||||
|
||||
`process.env` now has the keys and values you defined in your `.env` file.
|
||||
|
||||
```javascript
|
||||
const db = require('db')
|
||||
db.connect({
|
||||
host: process.env.DB_HOST,
|
||||
username: process.env.DB_USER,
|
||||
password: process.env.DB_PASS
|
||||
})
|
||||
```
|
||||
|
||||
### Preload
|
||||
|
||||
You can use the `--require` (`-r`) [command line option](https://nodejs.org/api/cli.html#cli_r_require_module) to preload dotenv. By doing this, you do not need to require and load dotenv in your application code. This is the preferred approach when using `import` instead of `require`.
|
||||
|
||||
```bash
|
||||
$ node -r dotenv/config your_script.js
|
||||
```
|
||||
|
||||
The configuration options below are supported as command line arguments in the format `dotenv_config_<option>=value`
|
||||
|
||||
```bash
|
||||
$ node -r dotenv/config your_script.js dotenv_config_path=/custom/path/to/your/env/vars
|
||||
```
|
||||
|
||||
Additionally, you can use environment variables to set configuration options. Command line arguments will precede these.
|
||||
|
||||
```bash
|
||||
$ DOTENV_CONFIG_<OPTION>=value node -r dotenv/config your_script.js
|
||||
```
|
||||
|
||||
```bash
|
||||
$ DOTENV_CONFIG_ENCODING=latin1 node -r dotenv/config your_script.js dotenv_config_path=/custom/path/to/.env
|
||||
```
|
||||
|
||||
## Config
|
||||
|
||||
`config` will read your `.env` file, parse the contents, assign it to
|
||||
[`process.env`](https://nodejs.org/docs/latest/api/process.html#process_process_env),
|
||||
and return an Object with a `parsed` key containing the loaded content or an `error` key if it failed.
|
||||
|
||||
```js
|
||||
const result = dotenv.config()
|
||||
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
}
|
||||
|
||||
console.log(result.parsed)
|
||||
```
|
||||
|
||||
You can additionally, pass options to `config`.
|
||||
|
||||
### Options
|
||||
|
||||
#### Path
|
||||
|
||||
Default: `path.resolve(process.cwd(), '.env')`
|
||||
|
||||
You may specify a custom path if your file containing environment variables is located elsewhere.
|
||||
|
||||
```js
|
||||
require('dotenv').config({ path: '/full/custom/path/to/your/env/vars' })
|
||||
```
|
||||
|
||||
#### Encoding
|
||||
|
||||
Default: `utf8`
|
||||
|
||||
You may specify the encoding of your file containing environment variables.
|
||||
|
||||
```js
|
||||
require('dotenv').config({ encoding: 'latin1' })
|
||||
```
|
||||
|
||||
#### Debug
|
||||
|
||||
Default: `false`
|
||||
|
||||
You may turn on logging to help debug why certain keys or values are not being set as you expect.
|
||||
|
||||
```js
|
||||
require('dotenv').config({ debug: process.env.DEBUG })
|
||||
```
|
||||
|
||||
## Parse
|
||||
|
||||
The engine which parses the contents of your file containing environment
|
||||
variables is available to use. It accepts a String or Buffer and will return
|
||||
an Object with the parsed keys and values.
|
||||
|
||||
```js
|
||||
const dotenv = require('dotenv')
|
||||
const buf = Buffer.from('BASIC=basic')
|
||||
const config = dotenv.parse(buf) // will return an object
|
||||
console.log(typeof config, config) // object { BASIC : 'basic' }
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
#### Debug
|
||||
|
||||
Default: `false`
|
||||
|
||||
You may turn on logging to help debug why certain keys or values are not being set as you expect.
|
||||
|
||||
```js
|
||||
const dotenv = require('dotenv')
|
||||
const buf = Buffer.from('hello world')
|
||||
const opt = { debug: true }
|
||||
const config = dotenv.parse(buf, opt)
|
||||
// expect a debug message because the buffer is not in KEY=VAL form
|
||||
```
|
||||
|
||||
### Rules
|
||||
|
||||
The parsing engine currently supports the following rules:
|
||||
|
||||
- `BASIC=basic` becomes `{BASIC: 'basic'}`
|
||||
- empty lines are skipped
|
||||
- lines beginning with `#` are treated as comments
|
||||
- empty values become empty strings (`EMPTY=` becomes `{EMPTY: ''}`)
|
||||
- inner quotes are maintained (think JSON) (`JSON={"foo": "bar"}` becomes `{JSON:"{\"foo\": \"bar\"}"`)
|
||||
- whitespace is removed from both ends of unquoted values (see more on [`trim`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)) (`FOO= some value ` becomes `{FOO: 'some value'}`)
|
||||
- single and double quoted values are escaped (`SINGLE_QUOTE='quoted'` becomes `{SINGLE_QUOTE: "quoted"}`)
|
||||
- single and double quoted values maintain whitespace from both ends (`FOO=" some value "` becomes `{FOO: ' some value '}`)
|
||||
- double quoted values expand new lines (`MULTILINE="new\nline"` becomes
|
||||
|
||||
```
|
||||
{MULTILINE: 'new
|
||||
line'}
|
||||
```
|
||||
|
||||
## FAQ
|
||||
|
||||
### Should I commit my `.env` file?
|
||||
|
||||
No. We **strongly** recommend against committing your `.env` file to version
|
||||
control. It should only include environment-specific values such as database
|
||||
passwords or API keys. Your production database should have a different
|
||||
password than your development database.
|
||||
|
||||
### Should I have multiple `.env` files?
|
||||
|
||||
No. We **strongly** recommend against having a "main" `.env` file and an "environment" `.env` file like `.env.test`. Your config should vary between deploys, and you should not be sharing values between environments.
|
||||
|
||||
> In a twelve-factor app, env vars are granular controls, each fully orthogonal to other env vars. They are never grouped together as “environments”, but instead are independently managed for each deploy. This is a model that scales up smoothly as the app naturally expands into more deploys over its lifetime.
|
||||
>
|
||||
> – [The Twelve-Factor App](http://12factor.net/config)
|
||||
|
||||
### What happens to environment variables that were already set?
|
||||
|
||||
We will never modify any environment variables that have already been set. In particular, if there is a variable in your `.env` file which collides with one that already exists in your environment, then that variable will be skipped. This behavior allows you to override all `.env` configurations with a machine-specific environment, although it is not recommended.
|
||||
|
||||
If you want to override `process.env` you can do something like this:
|
||||
|
||||
```javascript
|
||||
const fs = require('fs')
|
||||
const dotenv = require('dotenv')
|
||||
const envConfig = dotenv.parse(fs.readFileSync('.env.override'))
|
||||
for (const k in envConfig) {
|
||||
process.env[k] = envConfig[k]
|
||||
}
|
||||
```
|
||||
|
||||
### Can I customize/write plugins for dotenv?
|
||||
|
||||
For `dotenv@2.x.x`: Yes. `dotenv.config()` now returns an object representing
|
||||
the parsed `.env` file. This gives you everything you need to continue
|
||||
setting values on `process.env`. For example:
|
||||
|
||||
```js
|
||||
const dotenv = require('dotenv')
|
||||
const variableExpansion = require('dotenv-expand')
|
||||
const myEnv = dotenv.config()
|
||||
variableExpansion(myEnv)
|
||||
```
|
||||
|
||||
### What about variable expansion?
|
||||
|
||||
Try [dotenv-expand](https://github.com/motdotla/dotenv-expand)
|
||||
|
||||
### How do I use dotenv with `import`?
|
||||
|
||||
ES2015 and beyond offers modules that allow you to `export` any top-level `function`, `class`, `var`, `let`, or `const`.
|
||||
|
||||
> When you run a module containing an `import` declaration, the modules it imports are loaded first, then each module body is executed in a depth-first traversal of the dependency graph, avoiding cycles by skipping anything already executed.
|
||||
>
|
||||
> – [ES6 In Depth: Modules](https://hacks.mozilla.org/2015/08/es6-in-depth-modules/)
|
||||
|
||||
You must run `dotenv.config()` before referencing any environment variables. Here's an example of problematic code:
|
||||
|
||||
`errorReporter.js`:
|
||||
|
||||
```js
|
||||
import { Client } from 'best-error-reporting-service'
|
||||
|
||||
export const client = new Client(process.env.BEST_API_KEY)
|
||||
```
|
||||
|
||||
`index.js`:
|
||||
|
||||
```js
|
||||
import dotenv from 'dotenv'
|
||||
import errorReporter from './errorReporter'
|
||||
|
||||
dotenv.config()
|
||||
errorReporter.client.report(new Error('faq example'))
|
||||
```
|
||||
|
||||
`client` will not be configured correctly because it was constructed before `dotenv.config()` was executed. There are (at least) 3 ways to make this work.
|
||||
|
||||
1. Preload dotenv: `node --require dotenv/config index.js` (_Note: you do not need to `import` dotenv with this approach_)
|
||||
2. Import `dotenv/config` instead of `dotenv` (_Note: you do not need to call `dotenv.config()` and must pass options via the command line or environment variables with this approach_)
|
||||
3. Create a separate file that will execute `config` first as outlined in [this comment on #133](https://github.com/motdotla/dotenv/issues/133#issuecomment-255298822)
|
||||
|
||||
## Contributing Guide
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
## Change Log
|
||||
|
||||
See [CHANGELOG.md](CHANGELOG.md)
|
||||
|
||||
## Who's using dotenv?
|
||||
|
||||
[These npm modules depend on it.](https://www.npmjs.com/browse/depended/dotenv)
|
||||
|
||||
Projects that expand it often use the [keyword "dotenv" on npm](https://www.npmjs.com/search?q=keywords:dotenv).
|
|
@ -0,0 +1,11 @@
|
|||
/* @flow */
|
||||
|
||||
(function () {
|
||||
require('./lib/main').config(
|
||||
Object.assign(
|
||||
{},
|
||||
require('./lib/env-options'),
|
||||
require('./lib/cli-options')(process.argv)
|
||||
)
|
||||
)
|
||||
})()
|
|
@ -0,0 +1,13 @@
|
|||
/* @flow */
|
||||
|
||||
const re = /^dotenv_config_(encoding|path|debug)=(.+)$/
|
||||
|
||||
module.exports = function optionMatcher (args /*: Array<string> */) {
|
||||
return args.reduce(function (acc, cur) {
|
||||
const matches = cur.match(re)
|
||||
if (matches) {
|
||||
acc[matches[1]] = matches[2]
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
/* @flow */
|
||||
|
||||
// ../config.js accepts options via environment variables
|
||||
const options = {}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_ENCODING != null) {
|
||||
options.encoding = process.env.DOTENV_CONFIG_ENCODING
|
||||
}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_PATH != null) {
|
||||
options.path = process.env.DOTENV_CONFIG_PATH
|
||||
}
|
||||
|
||||
if (process.env.DOTENV_CONFIG_DEBUG != null) {
|
||||
options.debug = process.env.DOTENV_CONFIG_DEBUG
|
||||
}
|
||||
|
||||
module.exports = options
|
|
@ -0,0 +1,113 @@
|
|||
/* @flow */
|
||||
/*::
|
||||
|
||||
type DotenvParseOptions = {
|
||||
debug?: boolean
|
||||
}
|
||||
|
||||
// keys and values from src
|
||||
type DotenvParseOutput = { [string]: string }
|
||||
|
||||
type DotenvConfigOptions = {
|
||||
path?: string, // path to .env file
|
||||
encoding?: string, // encoding of .env file
|
||||
debug?: string // turn on logging for debugging purposes
|
||||
}
|
||||
|
||||
type DotenvConfigOutput = {
|
||||
parsed?: DotenvParseOutput,
|
||||
error?: Error
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
function log (message /*: string */) {
|
||||
console.log(`[dotenv][DEBUG] ${message}`)
|
||||
}
|
||||
|
||||
const NEWLINE = '\n'
|
||||
const RE_INI_KEY_VAL = /^\s*([\w.-]+)\s*=\s*(.*)?\s*$/
|
||||
const RE_NEWLINES = /\\n/g
|
||||
const NEWLINES_MATCH = /\n|\r|\r\n/
|
||||
|
||||
// Parses src into an Object
|
||||
function parse (src /*: string | Buffer */, options /*: ?DotenvParseOptions */) /*: DotenvParseOutput */ {
|
||||
const debug = Boolean(options && options.debug)
|
||||
const obj = {}
|
||||
|
||||
// convert Buffers before splitting into lines and processing
|
||||
src.toString().split(NEWLINES_MATCH).forEach(function (line, idx) {
|
||||
// matching "KEY' and 'VAL' in 'KEY=VAL'
|
||||
const keyValueArr = line.match(RE_INI_KEY_VAL)
|
||||
// matched?
|
||||
if (keyValueArr != null) {
|
||||
const key = keyValueArr[1]
|
||||
// default undefined or missing values to empty string
|
||||
let val = (keyValueArr[2] || '')
|
||||
const end = val.length - 1
|
||||
const isDoubleQuoted = val[0] === '"' && val[end] === '"'
|
||||
const isSingleQuoted = val[0] === "'" && val[end] === "'"
|
||||
|
||||
// if single or double quoted, remove quotes
|
||||
if (isSingleQuoted || isDoubleQuoted) {
|
||||
val = val.substring(1, end)
|
||||
|
||||
// if double quoted, expand newlines
|
||||
if (isDoubleQuoted) {
|
||||
val = val.replace(RE_NEWLINES, NEWLINE)
|
||||
}
|
||||
} else {
|
||||
// remove surrounding whitespace
|
||||
val = val.trim()
|
||||
}
|
||||
|
||||
obj[key] = val
|
||||
} else if (debug) {
|
||||
log(`did not match key and value when parsing line ${idx + 1}: ${line}`)
|
||||
}
|
||||
})
|
||||
|
||||
return obj
|
||||
}
|
||||
|
||||
// Populates process.env from .env file
|
||||
function config (options /*: ?DotenvConfigOptions */) /*: DotenvConfigOutput */ {
|
||||
let dotenvPath = path.resolve(process.cwd(), '.env')
|
||||
let encoding /*: string */ = 'utf8'
|
||||
let debug = false
|
||||
|
||||
if (options) {
|
||||
if (options.path != null) {
|
||||
dotenvPath = options.path
|
||||
}
|
||||
if (options.encoding != null) {
|
||||
encoding = options.encoding
|
||||
}
|
||||
if (options.debug != null) {
|
||||
debug = true
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// specifying an encoding returns a string instead of a buffer
|
||||
const parsed = parse(fs.readFileSync(dotenvPath, { encoding }), { debug })
|
||||
|
||||
Object.keys(parsed).forEach(function (key) {
|
||||
if (!Object.prototype.hasOwnProperty.call(process.env, key)) {
|
||||
process.env[key] = parsed[key]
|
||||
} else if (debug) {
|
||||
log(`"${key}" is already defined in \`process.env\` and will not be overwritten`)
|
||||
}
|
||||
})
|
||||
|
||||
return { parsed }
|
||||
} catch (e) {
|
||||
return { error: e }
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.config = config
|
||||
module.exports.parse = parse
|
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"_from": "dotenv",
|
||||
"_id": "dotenv@8.2.0",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==",
|
||||
"_location": "/dotenv",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "tag",
|
||||
"registry": true,
|
||||
"raw": "dotenv",
|
||||
"name": "dotenv",
|
||||
"escapedName": "dotenv",
|
||||
"rawSpec": "",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "latest"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"#USER",
|
||||
"/"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"_shasum": "97e619259ada750eea3e4ea3e26bceea5424b16a",
|
||||
"_spec": "dotenv",
|
||||
"_where": "C:\\Priyathamwork\\locaft\\locaft\\auth",
|
||||
"bugs": {
|
||||
"url": "https://github.com/motdotla/dotenv/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"dependencies": {},
|
||||
"deprecated": false,
|
||||
"description": "Loads environment variables from .env file",
|
||||
"devDependencies": {
|
||||
"decache": "^4.5.1",
|
||||
"dtslint": "^0.9.8",
|
||||
"flow-bin": "^0.109.0",
|
||||
"sinon": "^7.5.0",
|
||||
"standard": "^13.1.0",
|
||||
"standard-markdown": "^5.1.0",
|
||||
"standard-version": "^7.0.0",
|
||||
"tap": "^14.7.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"homepage": "https://github.com/motdotla/dotenv#readme",
|
||||
"keywords": [
|
||||
"dotenv",
|
||||
"env",
|
||||
".env",
|
||||
"environment",
|
||||
"variables",
|
||||
"config",
|
||||
"settings"
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"main": "lib/main.js",
|
||||
"name": "dotenv",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/motdotla/dotenv.git"
|
||||
},
|
||||
"scripts": {
|
||||
"dtslint": "dtslint types",
|
||||
"flow": "flow",
|
||||
"lint": "standard",
|
||||
"postlint": "standard-markdown",
|
||||
"prerelease": "npm test",
|
||||
"pretest": "npm run lint && npm run dtslint",
|
||||
"release": "standard-version",
|
||||
"test": "tap tests/*.js --100"
|
||||
},
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"flow-typed/"
|
||||
]
|
||||
},
|
||||
"types": "types",
|
||||
"version": "8.2.0"
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
// TypeScript Version: 3.0
|
||||
/// <reference types="node" />
|
||||
|
||||
export interface DotenvParseOptions {
|
||||
/**
|
||||
* You may turn on logging to help debug why certain keys or values are not being set as you expect.
|
||||
*/
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export interface DotenvParseOutput {
|
||||
[name: string]: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string or buffer in the .env file format into an object.
|
||||
*
|
||||
* @param src - contents to be parsed
|
||||
* @param options - additional options
|
||||
* @returns an object with keys and values based on `src`
|
||||
*/
|
||||
export function parse(
|
||||
src: string | Buffer,
|
||||
options?: DotenvParseOptions
|
||||
): DotenvParseOutput;
|
||||
|
||||
export interface DotenvConfigOptions {
|
||||
/**
|
||||
* You may specify a custom path if your file containing environment variables is located elsewhere.
|
||||
*/
|
||||
path?: string;
|
||||
|
||||
/**
|
||||
* You may specify the encoding of your file containing environment variables.
|
||||
*/
|
||||
encoding?: string;
|
||||
|
||||
/**
|
||||
* You may turn on logging to help debug why certain keys or values are not being set as you expect.
|
||||
*/
|
||||
debug?: boolean;
|
||||
}
|
||||
|
||||
export interface DotenvConfigOutput {
|
||||
error?: Error;
|
||||
parsed?: DotenvParseOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads `.env` file contents into {@link https://nodejs.org/api/process.html#process_process_env | `process.env`}.
|
||||
* Example: 'KEY=value' becomes { parsed: { KEY: 'value' } }
|
||||
*
|
||||
* @param options - controls behavior
|
||||
* @returns an object with a `parsed` key if successful or `error` key if an error occurred
|
||||
*
|
||||
*/
|
||||
export function config(options?: DotenvConfigOptions): DotenvConfigOutput;
|
||||
/** @deprecated since v7.0.0 Use config instead. */
|
||||
export const load: typeof config;
|
|
@ -0,0 +1,19 @@
|
|||
import { config, parse } from "dotenv";
|
||||
|
||||
const env = config();
|
||||
const dbUrl: string | null =
|
||||
env.error || !env.parsed ? null : env.parsed["BASIC"];
|
||||
|
||||
config({
|
||||
path: ".env-example",
|
||||
encoding: "utf8",
|
||||
debug: true
|
||||
});
|
||||
|
||||
const parsed = parse("NODE_ENV=production\nDB_HOST=a.b.c");
|
||||
const dbHost: string = parsed["DB_HOST"];
|
||||
|
||||
const parsedFromBuffer = parse(new Buffer("JUSTICE=league\n"), {
|
||||
debug: true
|
||||
});
|
||||
const justice: string = parsedFromBuffer["JUSTICE"];
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"lib": ["es6"],
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"strictNullChecks": true,
|
||||
"strictFunctionTypes": true,
|
||||
"noEmit": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"dotenv": ["."]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"extends": "dtslint/dtslint.json",
|
||||
"rules": {
|
||||
"strict-export-declare-modifiers": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
object-assign
|
||||
(c) Sindre Sorhus
|
||||
@license MIT
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
/* eslint-disable no-unused-vars */
|
||||
var getOwnPropertySymbols = Object.getOwnPropertySymbols;
|
||||
var hasOwnProperty = Object.prototype.hasOwnProperty;
|
||||
var propIsEnumerable = Object.prototype.propertyIsEnumerable;
|
||||
|
||||
function toObject(val) {
|
||||
if (val === null || val === undefined) {
|
||||
throw new TypeError('Object.assign cannot be called with null or undefined');
|
||||
}
|
||||
|
||||
return Object(val);
|
||||
}
|
||||
|
||||
function shouldUseNative() {
|
||||
try {
|
||||
if (!Object.assign) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Detect buggy property enumeration order in older V8 versions.
|
||||
|
||||
// https://bugs.chromium.org/p/v8/issues/detail?id=4118
|
||||
var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
|
||||
test1[5] = 'de';
|
||||
if (Object.getOwnPropertyNames(test1)[0] === '5') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
|
||||
var test2 = {};
|
||||
for (var i = 0; i < 10; i++) {
|
||||
test2['_' + String.fromCharCode(i)] = i;
|
||||
}
|
||||
var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
|
||||
return test2[n];
|
||||
});
|
||||
if (order2.join('') !== '0123456789') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://bugs.chromium.org/p/v8/issues/detail?id=3056
|
||||
var test3 = {};
|
||||
'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
|
||||
test3[letter] = letter;
|
||||
});
|
||||
if (Object.keys(Object.assign({}, test3)).join('') !==
|
||||
'abcdefghijklmnopqrst') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (err) {
|
||||
// We don't expect any of the above to throw, but better to be safe.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = shouldUseNative() ? Object.assign : function (target, source) {
|
||||
var from;
|
||||
var to = toObject(target);
|
||||
var symbols;
|
||||
|
||||
for (var s = 1; s < arguments.length; s++) {
|
||||
from = Object(arguments[s]);
|
||||
|
||||
for (var key in from) {
|
||||
if (hasOwnProperty.call(from, key)) {
|
||||
to[key] = from[key];
|
||||
}
|
||||
}
|
||||
|
||||
if (getOwnPropertySymbols) {
|
||||
symbols = getOwnPropertySymbols(from);
|
||||
for (var i = 0; i < symbols.length; i++) {
|
||||
if (propIsEnumerable.call(from, symbols[i])) {
|
||||
to[symbols[i]] = from[symbols[i]];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return to;
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
|
||||
|
||||
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.
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"_from": "object-assign@^4",
|
||||
"_id": "object-assign@4.1.1",
|
||||
"_inBundle": false,
|
||||
"_integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||
"_location": "/object-assign",
|
||||
"_phantomChildren": {},
|
||||
"_requested": {
|
||||
"type": "range",
|
||||
"registry": true,
|
||||
"raw": "object-assign@^4",
|
||||
"name": "object-assign",
|
||||
"escapedName": "object-assign",
|
||||
"rawSpec": "^4",
|
||||
"saveSpec": null,
|
||||
"fetchSpec": "^4"
|
||||
},
|
||||
"_requiredBy": [
|
||||
"/cors"
|
||||
],
|
||||
"_resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"_shasum": "2109adc7965887cfc05cbbd442cac8bfbb360863",
|
||||
"_spec": "object-assign@^4",
|
||||
"_where": "C:\\Priyathamwork\\locaft\\locaft\\auth\\node_modules\\cors",
|
||||
"author": {
|
||||
"name": "Sindre Sorhus",
|
||||
"email": "sindresorhus@gmail.com",
|
||||
"url": "sindresorhus.com"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/sindresorhus/object-assign/issues"
|
||||
},
|
||||
"bundleDependencies": false,
|
||||
"deprecated": false,
|
||||
"description": "ES2015 `Object.assign()` ponyfill",
|
||||
"devDependencies": {
|
||||
"ava": "^0.16.0",
|
||||
"lodash": "^4.16.4",
|
||||
"matcha": "^0.7.0",
|
||||
"xo": "^0.16.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"homepage": "https://github.com/sindresorhus/object-assign#readme",
|
||||
"keywords": [
|
||||
"object",
|
||||
"assign",
|
||||
"extend",
|
||||
"properties",
|
||||
"es2015",
|
||||
"ecmascript",
|
||||
"harmony",
|
||||
"ponyfill",
|
||||
"prollyfill",
|
||||
"polyfill",
|
||||
"shim",
|
||||
"browser"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "object-assign",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/sindresorhus/object-assign.git"
|
||||
},
|
||||
"scripts": {
|
||||
"bench": "matcha bench.js",
|
||||
"test": "xo && ava"
|
||||
},
|
||||
"version": "4.1.1"
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
# object-assign [](https://travis-ci.org/sindresorhus/object-assign)
|
||||
|
||||
> ES2015 [`Object.assign()`](http://www.2ality.com/2014/01/object-assign.html) [ponyfill](https://ponyfill.com)
|
||||
|
||||
|
||||
## Use the built-in
|
||||
|
||||
Node.js 4 and up, as well as every evergreen browser (Chrome, Edge, Firefox, Opera, Safari),
|
||||
support `Object.assign()` :tada:. If you target only those environments, then by all
|
||||
means, use `Object.assign()` instead of this package.
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
```
|
||||
$ npm install --save object-assign
|
||||
```
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
const objectAssign = require('object-assign');
|
||||
|
||||
objectAssign({foo: 0}, {bar: 1});
|
||||
//=> {foo: 0, bar: 1}
|
||||
|
||||
// multiple sources
|
||||
objectAssign({foo: 0}, {bar: 1}, {baz: 2});
|
||||
//=> {foo: 0, bar: 1, baz: 2}
|
||||
|
||||
// overwrites equal keys
|
||||
objectAssign({foo: 0}, {foo: 1}, {foo: 2});
|
||||
//=> {foo: 2}
|
||||
|
||||
// ignores null and undefined sources
|
||||
objectAssign({foo: 0}, null, {bar: 1}, undefined);
|
||||
//=> {foo: 0, bar: 1}
|
||||
```
|
||||
|
||||
|
||||
## API
|
||||
|
||||
### objectAssign(target, [source, ...])
|
||||
|
||||
Assigns enumerable own properties of `source` objects to the `target` object and returns the `target` object. Additional `source` objects will overwrite previous ones.
|
||||
|
||||
|
||||
## Resources
|
||||
|
||||
- [ES2015 spec - Object.assign](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign)
|
||||
|
||||
|
||||
## Related
|
||||
|
||||
- [deep-assign](https://github.com/sindresorhus/deep-assign) - Recursive `Object.assign()`
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT © [Sindre Sorhus](https://sindresorhus.com)
|
|
@ -314,6 +314,11 @@
|
|||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
|
||||
},
|
||||
"context": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/context/-/context-1.1.0.tgz",
|
||||
"integrity": "sha512-nfNLy6MbBleZuK0vDwxUnYyu1McpjaZIHo7a3+yNoLWEJtnUjnB4z5xYZhg3XmVcCflh5U2FeaHbHUfCCLSeHA=="
|
||||
},
|
||||
"cookie": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
|
||||
|
@ -329,6 +334,15 @@
|
|||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"requires": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
}
|
||||
},
|
||||
"crypto-random-string": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
|
||||
|
@ -383,6 +397,11 @@
|
|||
"is-obj": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"dotenv": {
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz",
|
||||
"integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw=="
|
||||
},
|
||||
"duplexer3": {
|
||||
"version": "0.1.4",
|
||||
"resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
|
||||
|
@ -1037,6 +1056,11 @@
|
|||
"resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz",
|
||||
"integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ=="
|
||||
},
|
||||
"object-assign": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
"dependencies": {
|
||||
"bcryptjs": "^2.4.3",
|
||||
"config": "^3.3.2",
|
||||
"context": "^1.1.0",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"express-validator": "^6.6.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
|
|
|
@ -1,120 +1,112 @@
|
|||
const express = require('express');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const bcrypt = require('bcryptjs');
|
||||
const router = express.Router();
|
||||
const { check,validationResult } = require('express-validator');
|
||||
const UserSchema = require('../schemas/User');
|
||||
const config = require('config');
|
||||
const router = require("express").Router();
|
||||
const bcrypt = require("bcryptjs");
|
||||
const jwt = require("jsonwebtoken");
|
||||
const auth = require("../middleware/auth");
|
||||
const User = require("../models/userModel");
|
||||
|
||||
router.post(
|
||||
'/register',
|
||||
[
|
||||
check('email','E-mail is required').isEmail(),
|
||||
check('password','Password is required').notEmpty()
|
||||
],
|
||||
async (req,res) =>{
|
||||
router.post("/register", async (req, res) => {
|
||||
try {
|
||||
|
||||
let { username,email,phonenumber,password} = req.body;
|
||||
let user = await UserSchema.findOne({ email });
|
||||
const errors = validationResult(req);
|
||||
if(!errors.isEmpty()){
|
||||
return res.status(401).json({ errors:errors.array()});
|
||||
}
|
||||
if(user){
|
||||
return res.status(401).json({ msg: "User already exists"});
|
||||
}
|
||||
|
||||
const salt = await bcrypt.genSalt(10);
|
||||
password = await bcrypt.hash(password,salt);
|
||||
// validate
|
||||
|
||||
user = new UserSchema({
|
||||
if (!email || !password || !passwordCheck)
|
||||
return res.status(400).json({ msg: "Not all fields have been entered." });
|
||||
if (password.length < 5)
|
||||
return res
|
||||
.status(400)
|
||||
.json({ msg: "The password needs to be at least 5 characters long." });
|
||||
if (password !== passwordCheck)
|
||||
return res
|
||||
.status(400)
|
||||
.json({ msg: "Enter the same password twice for verification." });
|
||||
|
||||
const existingUser = await User.findOne({ email: email });
|
||||
if (existingUser)
|
||||
return res
|
||||
.status(400)
|
||||
.json({ msg: "An account with this email already exists." });
|
||||
|
||||
if (!username) username = email;
|
||||
|
||||
const salt = await bcrypt.genSalt();
|
||||
const passwordHash = await bcrypt.hash(password, salt);
|
||||
|
||||
const newUser = new User({
|
||||
username,
|
||||
email,
|
||||
phonenumber,
|
||||
password
|
||||
password: passwordHash,
|
||||
});
|
||||
const savedUser = await newUser.save();
|
||||
res.json(savedUser);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
|
||||
await user.save();
|
||||
|
||||
const payload = {
|
||||
user: {
|
||||
id: user.id,
|
||||
|
||||
}
|
||||
}
|
||||
jwt.sign(
|
||||
payload,
|
||||
config.get('jwtSecret'),
|
||||
(err,token) =>{
|
||||
if(err) throw err;
|
||||
res.json({ token });
|
||||
}
|
||||
|
||||
)
|
||||
//res.send("cred received");
|
||||
|
||||
} catch(error) {
|
||||
console.log(error.message);
|
||||
return res.status(500).json({ msg: "Server Error..."});
|
||||
}
|
||||
|
||||
}
|
||||
)
|
||||
router.post(
|
||||
'/login',
|
||||
[
|
||||
check('email',"Type valid e-mail").isEmail(),
|
||||
check('password','Passoword is required').notEmpty()
|
||||
],
|
||||
async (req,res) => {
|
||||
router.post("/login", async (req, res) => {
|
||||
try {
|
||||
|
||||
const { email, password } = req.body;
|
||||
|
||||
let user = await UserSchema.findOne({ email });
|
||||
const errors = validationResult(req);
|
||||
// validate
|
||||
if (!email || !password)
|
||||
return res.status(400).json({ msg: "Not all fields have been entered." });
|
||||
|
||||
if(!errors.isEmpty()){
|
||||
return res.status(401).json({
|
||||
errors: errors.array()
|
||||
});
|
||||
}
|
||||
const user = await User.findOne({ email: email });
|
||||
if (!user)
|
||||
return res
|
||||
.status(400)
|
||||
.json({ msg: "No account with this email has been registered." });
|
||||
|
||||
if(!user) {
|
||||
return res.status(401).json({ msg: "This user doesn't exists"});
|
||||
}
|
||||
const isMatch = await bcrypt.compare(password, user.password);
|
||||
if (!isMatch) return res.status(400).json({ msg: "Invalid credentials." });
|
||||
|
||||
let isPassowardMatch = await bcrypt.compare(password,user.password);
|
||||
|
||||
if(isPassowardMatch){
|
||||
const payload = {
|
||||
const token = jwt.sign({ id: user._id }, process.env.JWT_SECRET);
|
||||
res.json({
|
||||
token,
|
||||
user: {
|
||||
id: user.id,
|
||||
|
||||
id: user._id,
|
||||
username: user.username,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
}
|
||||
jwt.sign(
|
||||
payload,
|
||||
config.get('jwtSecret'),
|
||||
(err,token) =>{
|
||||
if(err) throw err;
|
||||
res.json({ token });
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
}else return res.status(401).json({
|
||||
msg:"incorrect Passoword"
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.log(error.message);
|
||||
return res.status(500).json({
|
||||
msg:"serve error ...."
|
||||
router.delete("/delete", auth, async (req, res) => {
|
||||
try {
|
||||
const deletedUser = await User.findByIdAndDelete(req.user);
|
||||
res.json(deletedUser);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
router.post("/tokenIsValid", async (req, res) => {
|
||||
try {
|
||||
const token = req.header("x-auth-token");
|
||||
if (!token) return res.json(false);
|
||||
|
||||
const verified = jwt.verify(token, process.env.JWT_SECRET);
|
||||
if (!verified) return res.json(false);
|
||||
|
||||
const user = await User.findById(verified.id);
|
||||
if (!user) return res.json(false);
|
||||
|
||||
return res.json(true);
|
||||
} catch (err) {
|
||||
res.status(500).json({ error: err.message });
|
||||
}
|
||||
)
|
||||
});
|
||||
|
||||
router.get("/", auth, async (req, res) => {
|
||||
const user = await User.findById(req.user);
|
||||
res.json({
|
||||
username: user.username,
|
||||
id: user._id,
|
||||
});
|
||||
});
|
||||
|
||||
module.exports = router;
|
|
@ -8,7 +8,8 @@ const UserSchema = mongoose.Schema({
|
|||
},
|
||||
email: {
|
||||
type: String,
|
||||
required:true
|
||||
required:true,
|
||||
unique: true
|
||||
},
|
||||
phonenumber: {
|
||||
type: Number,
|
||||
|
@ -17,9 +18,10 @@ const UserSchema = mongoose.Schema({
|
|||
},
|
||||
password: {
|
||||
type:String,
|
||||
required:true
|
||||
required:true,
|
||||
minlength: 5
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('user',UserSchema);
|
||||
module.exports = User = mongoose.model('user',UserSchema);
|
|
@ -1,14 +1,33 @@
|
|||
const express = require('express');
|
||||
require("dotenv").config();
|
||||
const express = require("express");
|
||||
const mongoose = require("mongoose");
|
||||
const cors = require("cors");
|
||||
|
||||
// set up express
|
||||
|
||||
const app = express();
|
||||
const connectToDb = require('./config/connectToDb');
|
||||
app.use(express.json());
|
||||
app.use(cors());
|
||||
|
||||
connectToDb();
|
||||
app.use(express.json({ extended: false }));
|
||||
const PORT = process.env.PORT || 6000;
|
||||
|
||||
app.use('/api/users',require('./routes/users'));
|
||||
app.listen(PORT, () => console.log(`The server has started on port: ${PORT}`));
|
||||
|
||||
// set up mongoose
|
||||
|
||||
let PORT = process.env.PORT || 6000;
|
||||
mongoose.connect(
|
||||
process.env.MONGODB_CONNECTION_STRING,
|
||||
{
|
||||
useNewUrlParser: true,
|
||||
useUnifiedTopology: true,
|
||||
useCreateIndex: true,
|
||||
},
|
||||
(err) => {
|
||||
if (err) throw err;
|
||||
console.log("MongoDB connection established");
|
||||
}
|
||||
);
|
||||
|
||||
app.listen(PORT,() => console.log(`server is running on port: ${PORT}`));
|
||||
// set up routes
|
||||
|
||||
app.use("/users", require("./routes/userRouter"));
|
|
@ -6,16 +6,6 @@
|
|||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
|
||||
const initalState = {
|
||||
token: localStorage.getItem('token'),
|
||||
isAllowedToLogin: false,
|
||||
errors:{}
|
||||
}
|
||||
|
||||
const authReducer = ( state=initialState, action ) => {
|
||||
const {type,payload} = action;
|
||||
switch(type){
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default authReducer;
|
|
@ -0,0 +1,10 @@
|
|||
import React from "react";
|
||||
|
||||
export default function ErrorNotice(props) {
|
||||
return (
|
||||
<div className="error-notice">
|
||||
<span>{props.message}</span>
|
||||
<button onClick={props.clearError}>X</button>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -1,9 +1,39 @@
|
|||
import React, {Component} from 'react';
|
||||
import React, { useState, useEffect, Component} from 'react';
|
||||
import '../navbar.css';
|
||||
import Axios from "axios";
|
||||
|
||||
class NavBar extends Component {
|
||||
export default function NavBar() {
|
||||
const [userData, setUserData] = useState({
|
||||
token: undefined,
|
||||
user: undefined,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const checkLoggedIn = async () => {
|
||||
let token = localStorage.getItem("auth-token");
|
||||
if (token === null) {
|
||||
localStorage.setItem("auth-token", "");
|
||||
token = "";
|
||||
}
|
||||
const tokenRes = await Axios.post(
|
||||
"http://localhost:5000/users/tokenIsValid",
|
||||
null,
|
||||
{ headers: { "x-auth-token": token } }
|
||||
);
|
||||
if (tokenRes.data) {
|
||||
const userRes = await Axios.get("http://localhost:5000/users/", {
|
||||
headers: { "x-auth-token": token },
|
||||
});
|
||||
setUserData({
|
||||
token,
|
||||
user: userRes.data,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
checkLoggedIn();
|
||||
}, []);
|
||||
|
||||
render(){
|
||||
window.addEventListener("scroll", () =>{
|
||||
var header = document.querySelector("header");
|
||||
header.classList.toggle("sticky",window.scrollY > 0);
|
||||
|
@ -24,6 +54,7 @@ class NavBar extends Component {
|
|||
<li><a href="#">About</a></li>
|
||||
<li><a href="#">Services</a></li>
|
||||
<li><a href="#">Contact us</a></li>
|
||||
<li><a href="#">Register</a></li>
|
||||
<li><a href="#">Log In</a></li>
|
||||
</ul>
|
||||
|
||||
|
@ -32,5 +63,4 @@ class NavBar extends Component {
|
|||
|
||||
)
|
||||
}
|
||||
}
|
||||
export default NavBar;
|
||||
|
||||
|
|
|
@ -1,46 +1,59 @@
|
|||
import React, { useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Provider } from 'react-redux';
|
||||
import store from './store';
|
||||
|
||||
import React, { useState, useContext } from "react";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import UserContext from "../context/UserContext";
|
||||
import Axios from "axios";
|
||||
import { Link } from "react-router-dom";
|
||||
import ErrorNotice from "./ErrorNotice";
|
||||
|
||||
const SignInForm = () => {
|
||||
|
||||
let [data,setData] = useState({
|
||||
email: '',
|
||||
password: ''
|
||||
const [email, setEmail] = useState();
|
||||
const [password, setPassword] = useState();
|
||||
const [error, setError] = useState();
|
||||
|
||||
const { setUserData } = useContext(UserContext);
|
||||
const history = useHistory();
|
||||
|
||||
const submit = async (e) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const loginUser = { email, password };
|
||||
const loginRes = await Axios.post(
|
||||
"http://localhost:5000/users/login",
|
||||
loginUser
|
||||
);
|
||||
setUserData({
|
||||
token: loginRes.data.token,
|
||||
user: loginRes.data.user,
|
||||
});
|
||||
|
||||
|
||||
const handleChange = e => {
|
||||
|
||||
setData({...data,[e.target.name]: e.target.value});
|
||||
|
||||
localStorage.setItem("auth-token", loginRes.data.token);
|
||||
history.push("/");
|
||||
} catch (err) {
|
||||
err.response.data.msg && setError(err.response.data.msg);
|
||||
}
|
||||
const submitData = () => {
|
||||
console.log(data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
let {email,password} = data;
|
||||
};
|
||||
return (
|
||||
|
||||
<div className="FormCenter">
|
||||
<Provider store={store}></Provider>
|
||||
<form className="FormFields">
|
||||
<form className="FormFields" onSubmit={submit}>
|
||||
<div className="FormField">
|
||||
<label className="FormField__Label" htmlFor="email">E-Mail Address</label>
|
||||
<input type="email" id="email" className="FormField__Input" value={ email } placeholder="Enter your email" name="email" onChange={(e) => handleChange(e)} />
|
||||
<input type="email" id="email" className="FormField__Input" value={ email } placeholder="Enter your email" name="email" onChange={(e) => setEmail(e.target.value)} />
|
||||
</div>
|
||||
|
||||
<div className="FormField">
|
||||
<label className="FormField__Label" htmlFor="password">Password</label>
|
||||
<input type="password" id="password" className="FormField__Input" value={ password } placeholder="Enter your password" name="password" onChange={(e) => handleChange(e)} />
|
||||
<input type="password" id="password" className="FormField__Input" value={ password } placeholder="Enter your password" name="password" onChange={(e) => setPassword(e.target.value)} />
|
||||
</div>
|
||||
|
||||
<div className="FormField">
|
||||
<button className="FormField__Button mr-20" onClick={() => submitData()}>Sign In</button> <Link exact to="/sign-up" className="FormField__Link">Not a member?</Link>
|
||||
<button className="FormField__Button mr-20" >Sign In</button> <Link exact to="/sign-up" className="FormField__Link">Not a member?</Link>
|
||||
</div>
|
||||
</form>
|
||||
{error && (
|
||||
<ErrorNotice message={error} clearError={() => setError(undefined)} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
import { createStore, applyMiddleware } from 'redux';
|
||||
import thunk from 'redux-thunk';
|
||||
import {composeWithDevTools } from 'redux-devtools-extension';
|
||||
import AuthReducer from './AuthReducer';
|
||||
|
||||
const middleWare = [thunk];
|
||||
|
||||
const initialState = {};
|
||||
|
||||
const store = createStore(
|
||||
AuthReducer,
|
||||
initialState,
|
||||
composeWithDevTools(applyMiddleware(...middleWare))
|
||||
|
||||
);
|
||||
|
||||
export default store;
|
|
@ -0,0 +1,3 @@
|
|||
import { createContext } from "react";
|
||||
|
||||
export default createContext(null);
|
|
@ -64,7 +64,7 @@ header ul li a {
|
|||
color: #fff;
|
||||
letter-spacing: 2px;
|
||||
font-weight: 500px;
|
||||
padding: 5px 0;
|
||||
padding: 3px 0;
|
||||
transition: 0.6s;
|
||||
|
||||
|
||||
|
@ -74,7 +74,8 @@ header ul li a:before{
|
|||
content: '';
|
||||
left:0;
|
||||
bottom: 0;
|
||||
height: 15px;
|
||||
height: 5px;
|
||||
text-decoration: none;
|
||||
width:100%;
|
||||
background: #ffffff;
|
||||
transform: scaleX(0);
|
||||
|
|
Loading…
Reference in New Issue