@accounts/server
Advanced tools
Comparing version 0.0.12-alpha.5e7e66f0 to 0.0.12-alpha.867eb639
@@ -6,3 +6,3 @@ 'use strict'; | ||
}); | ||
exports.AccountsServer = undefined; | ||
exports.AccountsServer = exports.ServerHooks = undefined; | ||
@@ -15,2 +15,6 @@ var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _events = require('events'); | ||
var _events2 = _interopRequireDefault(_events); | ||
var _jsonwebtoken = require('jsonwebtoken'); | ||
@@ -44,2 +48,17 @@ | ||
var ServerHooks = exports.ServerHooks = { | ||
LoginSuccess: 'LoginSuccess', | ||
LoginError: 'LoginError', | ||
LogoutSuccess: 'LogoutSuccess', | ||
LogoutError: 'LogoutError', | ||
CreateUserSuccess: 'CreateUserSuccess', | ||
CreateUserError: 'CreateUserError', | ||
ResumeSessionSuccess: 'ResumeSessionSuccess', | ||
ResumeSessionError: 'ResumeSessionError', | ||
RefreshTokensSuccess: 'RefreshTokensSuccess', | ||
RefreshTokensError: 'RefreshTokensError', | ||
ImpersonationSuccess: 'ImpersonationSuccess', | ||
ImpersonationError: 'ImpersonationError' | ||
}; | ||
var AccountsServer = exports.AccountsServer = function () { | ||
@@ -72,2 +91,6 @@ function AccountsServer() { | ||
this.emailTemplates = _emailTemplates2.default; | ||
if (!this.hooks) { | ||
this.hooks = new _events2.default(); | ||
} | ||
} | ||
@@ -85,2 +108,62 @@ | ||
} | ||
}, { | ||
key: 'onLoginSuccess', | ||
value: function onLoginSuccess(callback) { | ||
return this._on(ServerHooks.LoginSuccess, callback); | ||
} | ||
}, { | ||
key: 'onLoginError', | ||
value: function onLoginError(callback) { | ||
return this._on(ServerHooks.LoginError, callback); | ||
} | ||
}, { | ||
key: 'onLogoutSuccess', | ||
value: function onLogoutSuccess(callback) { | ||
return this._on(ServerHooks.LogoutSuccess, callback); | ||
} | ||
}, { | ||
key: 'onLogoutError', | ||
value: function onLogoutError(callback) { | ||
return this._on(ServerHooks.LogoutError, callback); | ||
} | ||
}, { | ||
key: 'onCreateUserSuccess', | ||
value: function onCreateUserSuccess(callback) { | ||
return this._on(ServerHooks.CreateUserSuccess, callback); | ||
} | ||
}, { | ||
key: 'onCreateUserError', | ||
value: function onCreateUserError(callback) { | ||
return this._on(ServerHooks.CreateUserError, callback); | ||
} | ||
}, { | ||
key: 'onResumeSessionSuccess', | ||
value: function onResumeSessionSuccess(callback) { | ||
return this._on(ServerHooks.ResumeSessionSuccess, callback); | ||
} | ||
}, { | ||
key: 'onResumeSessionError', | ||
value: function onResumeSessionError(callback) { | ||
return this._on(ServerHooks.ResumeSessionError, callback); | ||
} | ||
}, { | ||
key: 'onRefreshTokensSuccess', | ||
value: function onRefreshTokensSuccess(callback) { | ||
return this._on(ServerHooks.RefreshTokensSuccess, callback); | ||
} | ||
}, { | ||
key: 'onRefreshTokensError', | ||
value: function onRefreshTokensError(callback) { | ||
return this._on(ServerHooks.RefreshTokensError, callback); | ||
} | ||
}, { | ||
key: 'onImpersonationSuccess', | ||
value: function onImpersonationSuccess(callback) { | ||
return this._on(ServerHooks.ImpersonationSuccess, callback); | ||
} | ||
}, { | ||
key: 'onImpersonationError', | ||
value: function onImpersonationError(callback) { | ||
return this._on(ServerHooks.ImpersonationError, callback); | ||
} | ||
@@ -101,3 +184,3 @@ /** | ||
var _ref = _asyncToGenerator(regeneratorRuntime.mark(function _callee(user, password, ip, userAgent) { | ||
var foundUser, sessionId, _createTokens, accessToken, refreshToken; | ||
var foundUser, sessionId, _createTokens, accessToken, refreshToken, loginResult; | ||
@@ -108,4 +191,6 @@ return regeneratorRuntime.wrap(function _callee$(_context) { | ||
case 0: | ||
_context.prev = 0; | ||
if (!(!user || !password)) { | ||
_context.next = 2; | ||
_context.next = 3; | ||
break; | ||
@@ -116,5 +201,5 @@ } | ||
case 2: | ||
case 3: | ||
if (!(!(0, _lodash.isString)(user) && !(0, _lodash.isPlainObject)(user) || !(0, _lodash.isString)(password))) { | ||
_context.next = 4; | ||
_context.next = 5; | ||
break; | ||
@@ -125,11 +210,10 @@ } | ||
case 4: | ||
case 5: | ||
foundUser = void 0; | ||
if (!this._options.passwordAuthenticator) { | ||
_context.next = 17; | ||
_context.next = 12; | ||
break; | ||
} | ||
_context.prev = 6; | ||
_context.next = 9; | ||
@@ -144,20 +228,11 @@ return this._externalPasswordAuthenticator(this._options.passwordAuthenticator, user, password); | ||
case 12: | ||
_context.prev = 12; | ||
_context.t0 = _context['catch'](6); | ||
throw new _common.AccountsError(_context.t0, user, 403); | ||
case 15: | ||
_context.next = 20; | ||
break; | ||
case 17: | ||
_context.next = 19; | ||
_context.next = 14; | ||
return this._defaultPasswordAuthenticator(user, password); | ||
case 19: | ||
case 14: | ||
foundUser = _context.sent; | ||
case 20: | ||
case 15: | ||
if (foundUser) { | ||
_context.next = 22; | ||
_context.next = 17; | ||
break; | ||
@@ -168,10 +243,10 @@ } | ||
case 22: | ||
_context.next = 24; | ||
case 17: | ||
_context.next = 19; | ||
return this.db.createSession(foundUser.id, ip, userAgent); | ||
case 24: | ||
case 19: | ||
sessionId = _context.sent; | ||
_createTokens = this.createTokens(sessionId), accessToken = _createTokens.accessToken, refreshToken = _createTokens.refreshToken; | ||
return _context.abrupt('return', { | ||
loginResult = { | ||
sessionId: sessionId, | ||
@@ -183,5 +258,18 @@ user: foundUser, | ||
} | ||
}); | ||
}; | ||
case 27: | ||
this.hooks.emit(ServerHooks.LoginSuccess, loginResult); | ||
return _context.abrupt('return', loginResult); | ||
case 26: | ||
_context.prev = 26; | ||
_context.t0 = _context['catch'](0); | ||
this.hooks.emit(ServerHooks.LoginError, _context.t0); | ||
throw _context.t0; | ||
case 30: | ||
case 'end': | ||
@@ -191,3 +279,3 @@ return _context.stop(); | ||
} | ||
}, _callee, this, [[6, 12]]); | ||
}, _callee, this, [[0, 26]]); | ||
})); | ||
@@ -349,3 +437,3 @@ | ||
var _ref5 = _asyncToGenerator(regeneratorRuntime.mark(function _callee4(user) { | ||
var password, _options, validateNewUser, onUserCreated, proposedUserObject, userId, createdUser; | ||
var password, _options, validateNewUser, proposedUserObject, userId; | ||
@@ -356,4 +444,6 @@ return regeneratorRuntime.wrap(function _callee4$(_context4) { | ||
case 0: | ||
_context4.prev = 0; | ||
if (!(!_common.validators.validateUsername(user.username) && !_common.validators.validateEmail(user.email))) { | ||
_context4.next = 2; | ||
_context4.next = 3; | ||
break; | ||
@@ -367,19 +457,19 @@ } | ||
case 2: | ||
case 3: | ||
_context4.t0 = user.username; | ||
if (!_context4.t0) { | ||
_context4.next = 7; | ||
_context4.next = 8; | ||
break; | ||
} | ||
_context4.next = 6; | ||
_context4.next = 7; | ||
return this.db.findUserByUsername(user.username); | ||
case 6: | ||
case 7: | ||
_context4.t0 = _context4.sent; | ||
case 7: | ||
case 8: | ||
if (!_context4.t0) { | ||
_context4.next = 9; | ||
_context4.next = 10; | ||
break; | ||
@@ -390,19 +480,19 @@ } | ||
case 9: | ||
case 10: | ||
_context4.t1 = user.email; | ||
if (!_context4.t1) { | ||
_context4.next = 14; | ||
_context4.next = 15; | ||
break; | ||
} | ||
_context4.next = 13; | ||
_context4.next = 14; | ||
return this.db.findUserByEmail(user.email); | ||
case 13: | ||
case 14: | ||
_context4.t1 = _context4.sent; | ||
case 14: | ||
case 15: | ||
if (!_context4.t1) { | ||
_context4.next = 16; | ||
_context4.next = 17; | ||
break; | ||
@@ -413,19 +503,18 @@ } | ||
case 16: | ||
case 17: | ||
password = void 0; | ||
if (!user.password) { | ||
_context4.next = 21; | ||
_context4.next = 22; | ||
break; | ||
} | ||
_context4.next = 20; | ||
_context4.next = 21; | ||
return this._hashAndBcryptPassword(user.password); | ||
case 20: | ||
case 21: | ||
password = _context4.sent; | ||
case 21: | ||
// TODO Accounts.onCreateUser | ||
_options = this.options(), validateNewUser = _options.validateNewUser, onUserCreated = _options.onUserCreated; | ||
case 22: | ||
_options = this.options(), validateNewUser = _options.validateNewUser; | ||
proposedUserObject = { | ||
@@ -439,33 +528,29 @@ username: user.username, | ||
if (!(0, _lodash.isFunction)(validateNewUser)) { | ||
_context4.next = 26; | ||
_context4.next = 27; | ||
break; | ||
} | ||
_context4.next = 26; | ||
_context4.next = 27; | ||
return validateNewUser(proposedUserObject); | ||
case 26: | ||
_context4.next = 28; | ||
case 27: | ||
_context4.next = 29; | ||
return this.db.createUser(proposedUserObject); | ||
case 28: | ||
case 29: | ||
userId = _context4.sent; | ||
if (!(0, _lodash.isFunction)(onUserCreated)) { | ||
_context4.next = 34; | ||
break; | ||
} | ||
this.hooks.emit(ServerHooks.CreateUserSuccess, userId, proposedUserObject); | ||
_context4.next = 32; | ||
return this.findUserById(userId); | ||
return _context4.abrupt('return', userId); | ||
case 32: | ||
createdUser = _context4.sent; | ||
case 34: | ||
_context4.prev = 34; | ||
_context4.t2 = _context4['catch'](0); | ||
onUserCreated(createdUser); | ||
this.hooks.emit(ServerHooks.CreateUserError, _context4.t2); | ||
case 34: | ||
return _context4.abrupt('return', userId); | ||
throw _context4.t2; | ||
case 35: | ||
case 38: | ||
case 'end': | ||
@@ -475,3 +560,3 @@ return _context4.stop(); | ||
} | ||
}, _callee4, this); | ||
}, _callee4, this, [[0, 34]]); | ||
})); | ||
@@ -485,3 +570,14 @@ | ||
}() | ||
}, { | ||
key: '_on', | ||
value: function _on(eventName, callback) { | ||
var _this = this; | ||
this.hooks.on(eventName, callback); | ||
return function () { | ||
return _this.hooks.removeListener(eventName, callback); | ||
}; | ||
} | ||
/** | ||
@@ -501,3 +597,3 @@ * @description Impersonate to another user. | ||
var _ref6 = _asyncToGenerator(regeneratorRuntime.mark(function _callee5(accessToken, username, ip, userAgent) { | ||
var session, user, impersonatedUser, isAuthorized, newSessionId, impersonationTokens; | ||
var session, user, impersonatedUser, isAuthorized, newSessionId, impersonationTokens, impersonationResult; | ||
return regeneratorRuntime.wrap(function _callee5$(_context5) { | ||
@@ -507,4 +603,6 @@ while (1) { | ||
case 0: | ||
_context5.prev = 0; | ||
if ((0, _lodash.isString)(accessToken)) { | ||
_context5.next = 2; | ||
_context5.next = 3; | ||
break; | ||
@@ -515,23 +613,23 @@ } | ||
case 2: | ||
_context5.prev = 2; | ||
case 3: | ||
_context5.prev = 3; | ||
_jsonwebtoken2.default.verify(accessToken, this._options.tokenSecret, { ignoreExpiration: true }); | ||
_context5.next = 9; | ||
_jsonwebtoken2.default.verify(accessToken, this._options.tokenSecret); | ||
_context5.next = 10; | ||
break; | ||
case 6: | ||
_context5.prev = 6; | ||
_context5.t0 = _context5['catch'](2); | ||
case 7: | ||
_context5.prev = 7; | ||
_context5.t0 = _context5['catch'](3); | ||
throw new _common.AccountsError('Access token is not valid'); | ||
case 9: | ||
_context5.next = 11; | ||
case 10: | ||
_context5.next = 12; | ||
return this.findSessionByAccessToken(accessToken); | ||
case 11: | ||
case 12: | ||
session = _context5.sent; | ||
if (session.valid) { | ||
_context5.next = 14; | ||
_context5.next = 15; | ||
break; | ||
@@ -542,11 +640,11 @@ } | ||
case 14: | ||
_context5.next = 16; | ||
case 15: | ||
_context5.next = 17; | ||
return this.db.findUserById(session.userId); | ||
case 16: | ||
case 17: | ||
user = _context5.sent; | ||
if (user) { | ||
_context5.next = 19; | ||
_context5.next = 20; | ||
break; | ||
@@ -557,11 +655,11 @@ } | ||
case 19: | ||
_context5.next = 21; | ||
case 20: | ||
_context5.next = 22; | ||
return this.db.findUserByUsername(username); | ||
case 21: | ||
case 22: | ||
impersonatedUser = _context5.sent; | ||
if (impersonatedUser) { | ||
_context5.next = 24; | ||
_context5.next = 25; | ||
break; | ||
@@ -572,5 +670,5 @@ } | ||
case 24: | ||
case 25: | ||
if (this._options.impersonationAuthorize) { | ||
_context5.next = 26; | ||
_context5.next = 27; | ||
break; | ||
@@ -581,11 +679,11 @@ } | ||
case 26: | ||
_context5.next = 28; | ||
case 27: | ||
_context5.next = 29; | ||
return this._options.impersonationAuthorize(user, impersonatedUser); | ||
case 28: | ||
case 29: | ||
isAuthorized = _context5.sent; | ||
if (isAuthorized) { | ||
_context5.next = 31; | ||
_context5.next = 32; | ||
break; | ||
@@ -596,16 +694,29 @@ } | ||
case 31: | ||
_context5.next = 33; | ||
case 32: | ||
_context5.next = 34; | ||
return this.db.createSession(impersonatedUser.id, ip, userAgent); | ||
case 33: | ||
case 34: | ||
newSessionId = _context5.sent; | ||
impersonationTokens = this.createTokens(newSessionId, true); | ||
return _context5.abrupt('return', { | ||
impersonationResult = { | ||
authorized: true, | ||
tokens: impersonationTokens, | ||
user: impersonatedUser | ||
}); | ||
}; | ||
case 36: | ||
this.hooks.emit(ServerHooks.ImpersonationSuccess, user, impersonationResult); | ||
return _context5.abrupt('return', impersonationResult); | ||
case 41: | ||
_context5.prev = 41; | ||
_context5.t1 = _context5['catch'](0); | ||
this.hooks.emit(ServerHooks.ImpersonationError, _context5.t1); | ||
throw _context5.t1; | ||
case 45: | ||
case 'end': | ||
@@ -615,3 +726,3 @@ return _context5.stop(); | ||
} | ||
}, _callee5, this, [[2, 6]]); | ||
}, _callee5, this, [[0, 41], [3, 7]]); | ||
})); | ||
@@ -640,3 +751,3 @@ | ||
var _ref7 = _asyncToGenerator(regeneratorRuntime.mark(function _callee6(accessToken, refreshToken, ip, userAgent) { | ||
var sessionId, decodedAccessToken, session, user, tokens; | ||
var sessionId, decodedAccessToken, session, user, tokens, result; | ||
return regeneratorRuntime.wrap(function _callee6$(_context6) { | ||
@@ -646,4 +757,6 @@ while (1) { | ||
case 0: | ||
_context6.prev = 0; | ||
if (!(!(0, _lodash.isString)(accessToken) || !(0, _lodash.isString)(refreshToken))) { | ||
_context6.next = 2; | ||
_context6.next = 3; | ||
break; | ||
@@ -654,5 +767,5 @@ } | ||
case 2: | ||
case 3: | ||
sessionId = void 0; | ||
_context6.prev = 3; | ||
_context6.prev = 4; | ||
@@ -665,19 +778,19 @@ _jsonwebtoken2.default.verify(refreshToken, this._options.tokenSecret); | ||
sessionId = decodedAccessToken.data.sessionId; | ||
_context6.next = 12; | ||
_context6.next = 13; | ||
break; | ||
case 9: | ||
_context6.prev = 9; | ||
_context6.t0 = _context6['catch'](3); | ||
case 10: | ||
_context6.prev = 10; | ||
_context6.t0 = _context6['catch'](4); | ||
throw new _common.AccountsError('Tokens are not valid'); | ||
case 12: | ||
_context6.next = 14; | ||
case 13: | ||
_context6.next = 15; | ||
return this.db.findSessionById(sessionId); | ||
case 14: | ||
case 15: | ||
session = _context6.sent; | ||
if (session) { | ||
_context6.next = 17; | ||
_context6.next = 18; | ||
break; | ||
@@ -688,16 +801,16 @@ } | ||
case 17: | ||
case 18: | ||
if (!session.valid) { | ||
_context6.next = 29; | ||
_context6.next = 32; | ||
break; | ||
} | ||
_context6.next = 20; | ||
_context6.next = 21; | ||
return this.db.findUserById(session.userId); | ||
case 20: | ||
case 21: | ||
user = _context6.sent; | ||
if (user) { | ||
_context6.next = 23; | ||
_context6.next = 24; | ||
break; | ||
@@ -708,18 +821,35 @@ } | ||
case 23: | ||
case 24: | ||
tokens = this.createTokens(sessionId); | ||
_context6.next = 26; | ||
_context6.next = 27; | ||
return this.db.updateSession(sessionId, ip, userAgent); | ||
case 26: | ||
return _context6.abrupt('return', { | ||
case 27: | ||
result = { | ||
sessionId: sessionId, | ||
user: user, | ||
tokens: tokens | ||
}); | ||
}; | ||
case 29: | ||
this.hooks.emit(ServerHooks.RefreshTokensSuccess, result); | ||
return _context6.abrupt('return', result); | ||
case 32: | ||
throw new _common.AccountsError('Session is no longer valid', { id: session.userId }); | ||
case 30: | ||
case 33: | ||
_context6.next = 39; | ||
break; | ||
case 35: | ||
_context6.prev = 35; | ||
_context6.t1 = _context6['catch'](0); | ||
this.hooks.emit(ServerHooks.RefreshTokensError, _context6.t1); | ||
throw _context6.t1; | ||
case 39: | ||
case 'end': | ||
@@ -729,3 +859,3 @@ return _context6.stop(); | ||
} | ||
}, _callee6, this, [[3, 9]]); | ||
}, _callee6, this, [[0, 35], [4, 10]]); | ||
})); | ||
@@ -787,21 +917,22 @@ | ||
case 0: | ||
_context7.next = 2; | ||
_context7.prev = 0; | ||
_context7.next = 3; | ||
return this.findSessionByAccessToken(accessToken); | ||
case 2: | ||
case 3: | ||
session = _context7.sent; | ||
if (!session.valid) { | ||
_context7.next = 13; | ||
_context7.next = 15; | ||
break; | ||
} | ||
_context7.next = 6; | ||
_context7.next = 7; | ||
return this.db.findUserById(session.userId); | ||
case 6: | ||
case 7: | ||
user = _context7.sent; | ||
if (user) { | ||
_context7.next = 9; | ||
_context7.next = 10; | ||
break; | ||
@@ -812,14 +943,27 @@ } | ||
case 9: | ||
_context7.next = 11; | ||
case 10: | ||
_context7.next = 12; | ||
return this.db.invalidateSession(session.sessionId); | ||
case 11: | ||
_context7.next = 14; | ||
case 12: | ||
this.hooks.emit(ServerHooks.LogoutSuccess, user, session, accessToken); | ||
_context7.next = 16; | ||
break; | ||
case 13: | ||
case 15: | ||
throw new _common.AccountsError('Session is no longer valid', { id: session.userId }); | ||
case 14: | ||
case 16: | ||
_context7.next = 22; | ||
break; | ||
case 18: | ||
_context7.prev = 18; | ||
_context7.t0 = _context7['catch'](0); | ||
this.hooks.emit(ServerHooks.LogoutError, _context7.t0); | ||
throw _context7.t0; | ||
case 22: | ||
case 'end': | ||
@@ -829,3 +973,3 @@ return _context7.stop(); | ||
} | ||
}, _callee7, this); | ||
}, _callee7, this, [[0, 18]]); | ||
})); | ||
@@ -848,21 +992,22 @@ | ||
case 0: | ||
_context8.next = 2; | ||
_context8.prev = 0; | ||
_context8.next = 3; | ||
return this.findSessionByAccessToken(accessToken); | ||
case 2: | ||
case 3: | ||
session = _context8.sent; | ||
if (!session.valid) { | ||
_context8.next = 19; | ||
_context8.next = 21; | ||
break; | ||
} | ||
_context8.next = 6; | ||
_context8.next = 7; | ||
return this.db.findUserById(session.userId); | ||
case 6: | ||
case 7: | ||
user = _context8.sent; | ||
if (user) { | ||
_context8.next = 9; | ||
_context8.next = 10; | ||
break; | ||
@@ -873,28 +1018,42 @@ } | ||
case 9: | ||
case 10: | ||
if (!this._options.resumeSessionValidator) { | ||
_context8.next = 18; | ||
_context8.next = 19; | ||
break; | ||
} | ||
_context8.prev = 10; | ||
_context8.next = 13; | ||
_context8.prev = 11; | ||
_context8.next = 14; | ||
return this._options.resumeSessionValidator(user, session); | ||
case 13: | ||
_context8.next = 18; | ||
case 14: | ||
_context8.next = 19; | ||
break; | ||
case 15: | ||
_context8.prev = 15; | ||
_context8.t0 = _context8['catch'](10); | ||
case 16: | ||
_context8.prev = 16; | ||
_context8.t0 = _context8['catch'](11); | ||
throw new _common.AccountsError(_context8.t0, { id: session.userId }, 403); | ||
case 18: | ||
case 19: | ||
this.hooks.emit(ServerHooks.ResumeSessionSuccess, user, accessToken); | ||
return _context8.abrupt('return', user); | ||
case 19: | ||
case 21: | ||
this.hooks.emit(ServerHooks.ResumeSessionError, new _common.AccountsError('Invalid Session', { id: session.userId })); | ||
return _context8.abrupt('return', null); | ||
case 20: | ||
case 25: | ||
_context8.prev = 25; | ||
_context8.t1 = _context8['catch'](0); | ||
this.hooks.emit(ServerHooks.ResumeSessionError, _context8.t1); | ||
throw _context8.t1; | ||
case 29: | ||
case 'end': | ||
@@ -904,3 +1063,3 @@ return _context8.stop(); | ||
} | ||
}, _callee8, this, [[10, 15]]); | ||
}, _callee8, this, [[0, 25], [11, 16]]); | ||
})); | ||
@@ -907,0 +1066,0 @@ |
{ | ||
"name": "@accounts/server", | ||
"version": "0.0.12-alpha.5e7e66f0", | ||
"version": "0.0.12-alpha.867eb639", | ||
"description": "Fullstack authentication and accounts-management", | ||
@@ -51,3 +51,3 @@ "main": "lib/index.js", | ||
"dependencies": { | ||
"@accounts/common": "^0.0.12-alpha.5e7e66f0", | ||
"@accounts/common": "^0.0.12-alpha.867eb639", | ||
"babel-polyfill": "^6.23.0", | ||
@@ -54,0 +54,0 @@ "bcryptjs": "^2.4.0", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
579243
42
7293