pax_global_header 0000666 0000000 0000000 00000000064 14123202540 0014503 g ustar 00root root 0000000 0000000 52 comment=f5dc1da878cff5135d60b31b8d99d33e48ab4161
passport-0.5.0/ 0000775 0000000 0000000 00000000000 14123202540 0013360 5 ustar 00root root 0000000 0000000 passport-0.5.0/.github/ 0000775 0000000 0000000 00000000000 14123202540 0014720 5 ustar 00root root 0000000 0000000 passport-0.5.0/.github/FUNDING.yml 0000664 0000000 0000000 00000000074 14123202540 0016536 0 ustar 00root root 0000000 0000000 github: jaredhanson
patreon: jaredhanson
ko_fi: jaredhanson
passport-0.5.0/.github/ISSUE_TEMPLATE.md 0000664 0000000 0000000 00000003551 14123202540 0017431 0 ustar 00root root 0000000 0000000 ** READ THIS FIRST! **
#### Are you looking for help?
Reminder: The issue tracker is not a support forum.
Issues should only be filed in this project once they are able to be reproduced
and confirmed as a flaw in the software or incorrect information in associated
documention.
If you are encountering problems integrating this module into your application,
please post a question on the [discussion forum](https://github.com/passport/discuss)
rather than filing an issue.
#### Is this a security issue?
Do not open issues that might have security implications. Potential security
vulnerabilities should be reported privately to jaredhanson@gmail.com. Once any
vulerabilities have been repaired, the details will be disclosed publicly in a
responsible manner. This also allows time for coordinating with affected parties
in order to mitigate negative consequences.
If neither of the above two scenarios apply to your situation, you should open
an issue. Delete this paragraph and the text above, and fill in the information
requested below.
### Expected behavior
### Actual behavior
### Steps to reproduce
```js
// Format code using Markdown code blocks
```
### Environment
* Operating System:
* Node version:
* passport version:
passport-0.5.0/.github/PULL_REQUEST_TEMPLATE.md 0000664 0000000 0000000 00000003562 14123202540 0020527 0 ustar 00root root 0000000 0000000 ** READ THIS FIRST! **
#### Are you implementing a new feature?
Requests for new features should first be discussed on the [developer forum](https://github.com/passport/develop).
This allows the community to gather feedback and assess whether or not there is
an existing way to achieve the desired functionality.
If it is determined that a new feature needs to be implemented, include a link
to the relevant discussion along with the pull request.
#### Is this a security patch?
Do not open pull requests that might have security implications. Potential
security vulnerabilities should be reported privately to jaredhanson@gmail.com.
Once any vulerabilities have been repaired, the details will be disclosed
publicly in a responsible manner. This also allows time for coordinating with
affected parties in order to mitigate negative consequences.
If neither of the above two scenarios apply to your situation, you should open
a pull request. Delete this paragraph and the text above, and fill in the
information requested below.
### Checklist
- [ ] I have read the [CONTRIBUTING](https://github.com/jaredhanson/passport/blob/master/CONTRIBUTING.md) guidelines.
- [ ] I have added test cases which verify the correct operation of this feature or patch.
- [ ] I have added documentation pertaining to this feature or patch.
- [ ] The automated test suite (`$ make test`) executes successfully.
- [ ] The automated code linting (`$ make lint`) executes successfully.
passport-0.5.0/.gitignore 0000664 0000000 0000000 00000000113 14123202540 0015343 0 ustar 00root root 0000000 0000000 docs/
reports/
# Mac OS X
.DS_Store
# Node.js
node_modules
npm-debug.log
passport-0.5.0/.jshintrc 0000664 0000000 0000000 00000000453 14123202540 0015207 0 ustar 00root root 0000000 0000000 {
"node": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"forin": true,
"immed": true,
"latedef": true,
"newcap": true,
"noarg": true,
"noempty": true,
"nonew": true,
"quotmark": "single",
"undef": true,
"unused": true,
"trailing": true,
"laxcomma": true
}
passport-0.5.0/.npmignore 0000664 0000000 0000000 00000000144 14123202540 0015356 0 ustar 00root root 0000000 0000000 CONTRIBUTING.md
Makefile
SPONSORS.md
docs/
examples/
reports/
test/
.github/
.jshintrc
.travis.yml
passport-0.5.0/.travis.yml 0000664 0000000 0000000 00000000541 14123202540 0015471 0 ustar 00root root 0000000 0000000 language: "node_js"
node_js:
- "13"
- "12"
- "11"
- "10"
- "9"
- "8"
- "7"
- "6"
- "5"
- "4"
- "3" # io.js
- "2" # io.js
- "1" # io.js
- "0.12"
- "0.10"
# - "0.8"
before_install:
- "npm install make-node@0.3.x -g"
- "preinstall-compat"
script:
- "make test-cov"
after_success:
- "make report-cov"
sudo: false
passport-0.5.0/CHANGELOG.md 0000664 0000000 0000000 00000001656 14123202540 0015201 0 ustar 00root root 0000000 0000000 # Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.5.0] - 2021-09-23
### Changed
- `initialize()` middleware extends request with `login()`, `logIn()`,
`logout()`, `logOut()`, `isAuthenticated()`, and `isUnauthenticated()`
functions.
### Removed
- `login()`, `logIn()`, `logout()`, `logOut()`, `isAuthenticated()`, and
`isUnauthenticated()` functions no longer added to `http.IncomingMessage.prototype`.
### Fixed
- `userProperty` option to `initialize()` middleware only affects the current
request, rather than all requests processed via singleton Passport instance,
eliminating a race condition in situations where `initialize()` middleware is
used multiple times in an application with `userProperty` set to different
values.
passport-0.5.0/CONTRIBUTING.md 0000664 0000000 0000000 00000000633 14123202540 0015613 0 ustar 00root root 0000000 0000000 ## Contributing
### Tests
The test suite is located in the `test/` directory. All new features are
expected to have corresponding test cases with complete code coverage. Patches
that increase test coverage are happily accepted.
Ensure that the test suite passes by executing:
```bash
$ make test
```
Coverage reports can be generated and viewed by executing:
```bash
$ make test-cov
$ make view-cov
```
passport-0.5.0/LICENSE 0000664 0000000 0000000 00000002074 14123202540 0014370 0 ustar 00root root 0000000 0000000 The MIT License (MIT)
Copyright (c) 2011-2019 Jared Hanson
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.
passport-0.5.0/Makefile 0000664 0000000 0000000 00000000630 14123202540 0015017 0 ustar 00root root 0000000 0000000 include node_modules/make-node/main.mk
SOURCES = lib/*.js lib/**/*.js
TESTS = test/*.test.js test/**/*.test.js
LCOVFILE = ./reports/coverage/lcov.info
MOCHAFLAGS = --require ./test/bootstrap/node
view-docs:
open ./docs/index.html
view-cov:
open ./reports/coverage/lcov-report/index.html
clean: clean-docs clean-cov
-rm -r $(REPORTSDIR)
clobber: clean
-rm -r node_modules
.PHONY: clean clobber
passport-0.5.0/README.md 0000664 0000000 0000000 00000021355 14123202540 0014645 0 ustar 00root root 0000000 0000000 [](http://passportjs.org)
# Passport
Passport is [Express](http://expressjs.com/)-compatible authentication
middleware for [Node.js](http://nodejs.org/).
Passport's sole purpose is to authenticate requests, which it does through an
extensible set of plugins known as _strategies_. Passport does not mount
routes or assume any particular database schema, which maximizes flexibility and
allows application-level decisions to be made by the developer. The API is
simple: you provide Passport a request to authenticate, and Passport provides
hooks for controlling what occurs when authentication succeeds or fails.
---
Sponsors

LoginRadius is built for the developer community to integrate robust Authentication and Single Sign-On in just a few lines of code.
FREE Signup

Your app, enterprise-ready.
Start selling to enterprise customers with just a few lines of code. Add Single Sign-On (and more) in minutes instead of months.
---
Status:
[](https://travis-ci.org/jaredhanson/passport)
[](https://coveralls.io/r/jaredhanson/passport)
[](https://david-dm.org/jaredhanson/passport)
## Install
```
$ npm install passport
```
## Usage
#### Strategies
Passport uses the concept of strategies to authenticate requests. Strategies
can range from verifying username and password credentials, delegated
authentication using [OAuth](http://oauth.net/) (for example, via [Facebook](http://www.facebook.com/)
or [Twitter](http://twitter.com/)), or federated authentication using [OpenID](http://openid.net/).
Before authenticating requests, the strategy (or strategies) used by an
application must be configured.
```javascript
passport.use(new LocalStrategy(
function(username, password, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (!user.verifyPassword(password)) { return done(null, false); }
return done(null, user);
});
}
));
```
There are 480+ strategies. Find the ones you want at: [passportjs.org](http://passportjs.org)
#### Sessions
Passport will maintain persistent login sessions. In order for persistent
sessions to work, the authenticated user must be serialized to the session, and
deserialized when subsequent requests are made.
Passport does not impose any restrictions on how your user records are stored.
Instead, you provide functions to Passport which implements the necessary
serialization and deserialization logic. In a typical application, this will be
as simple as serializing the user ID, and finding the user by ID when
deserializing.
```javascript
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
```
#### Middleware
To use Passport in an [Express](http://expressjs.com/) or
[Connect](http://senchalabs.github.com/connect/)-based application, configure it
with the required `passport.initialize()` middleware. If your application uses
persistent login sessions (recommended, but not required), `passport.session()`
middleware must also be used.
```javascript
var app = express();
app.use(require('serve-static')(__dirname + '/../../public'));
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
```
#### Authenticate Requests
Passport provides an `authenticate()` function, which is used as route
middleware to authenticate requests.
```javascript
app.post('/login',
passport.authenticate('local', { failureRedirect: '/login' }),
function(req, res) {
res.redirect('/');
});
```
## Strategies
Passport has a comprehensive set of **over 480** authentication strategies
covering social networking, enterprise integration, API services, and more.
## Search all strategies
There is a **Strategy Search** at [passportjs.org](http://passportjs.org)
The following table lists commonly used strategies:
|Strategy | Protocol |Developer |
|---------------------------------------------------------------|--------------------------|------------------------------------------------|
|[Local](https://github.com/jaredhanson/passport-local) | HTML form |[Jared Hanson](https://github.com/jaredhanson) |
|[OpenID](https://github.com/jaredhanson/passport-openid) | OpenID |[Jared Hanson](https://github.com/jaredhanson) |
|[BrowserID](https://github.com/jaredhanson/passport-browserid) | BrowserID |[Jared Hanson](https://github.com/jaredhanson) |
|[Facebook](https://github.com/jaredhanson/passport-facebook) | OAuth 2.0 |[Jared Hanson](https://github.com/jaredhanson) |
|[Google](https://github.com/jaredhanson/passport-google) | OpenID |[Jared Hanson](https://github.com/jaredhanson) |
|[Google](https://github.com/jaredhanson/passport-google-oauth) | OAuth / OAuth 2.0 |[Jared Hanson](https://github.com/jaredhanson) |
|[Twitter](https://github.com/jaredhanson/passport-twitter) | OAuth |[Jared Hanson](https://github.com/jaredhanson) |
|[Azure Active Directory](https://github.com/AzureAD/passport-azure-ad) | OAuth 2.0 / OpenID / SAML |[Azure](https://github.com/azuread) |
## Examples
- For a complete, working example, refer to the [example](https://github.com/passport/express-4.x-local-example)
that uses [passport-local](https://github.com/jaredhanson/passport-local).
- **Local Strategy**: Refer to the following tutorials for setting up user authentication via LocalStrategy (`passport-local`):
- Mongo
- Express v3x - [Tutorial](http://mherman.org/blog/2016/09/25/node-passport-and-postgres/#.V-govpMrJE5) / [working example](https://github.com/mjhea0/passport-local-knex)
- Express v4x - [Tutorial](http://mherman.org/blog/2015/01/31/local-authentication-with-passport-and-express-4/) / [working example](https://github.com/mjhea0/passport-local-express4)
- Postgres
- [Tutorial](http://mherman.org/blog/2015/01/31/local-authentication-with-passport-and-express-4/) / [working example](https://github.com/mjhea0/passport-local-express4)
- **Social Authentication**: Refer to the following tutorials for setting up various social authentication strategies:
- Express v3x - [Tutorial](http://mherman.org/blog/2013/11/10/social-authentication-with-passport-dot-js/) / [working example](https://github.com/mjhea0/passport-examples)
- Express v4x - [Tutorial](http://mherman.org/blog/2015/09/26/social-authentication-in-node-dot-js-with-passport) / [working example](https://github.com/mjhea0/passport-social-auth)
## Related Modules
- [Locomotive](https://github.com/jaredhanson/locomotive) — Powerful MVC web framework
- [OAuthorize](https://github.com/jaredhanson/oauthorize) — OAuth service provider toolkit
- [OAuth2orize](https://github.com/jaredhanson/oauth2orize) — OAuth 2.0 authorization server toolkit
- [connect-ensure-login](https://github.com/jaredhanson/connect-ensure-login) — middleware to ensure login sessions
The [modules](https://github.com/jaredhanson/passport/wiki/Modules) page on the
[wiki](https://github.com/jaredhanson/passport/wiki) lists other useful modules
that build upon or integrate with Passport.
## License
[The MIT License](http://opensource.org/licenses/MIT)
Copyright (c) 2011-2019 Jared Hanson <[http://jaredhanson.net/](http://jaredhanson.net/)>
passport-0.5.0/SPONSORS.md 0000664 0000000 0000000 00000000577 14123202540 0015201 0 ustar 00root root 0000000 0000000 ## Gold Sponsors
[](https://www.loginradius.com/)
[](https://workos.com/)
## Sponsors
- [CodePilot.ai](https://codepilot.ai/)
- Kelly Burke
- [Matt Miller](https://mmiller.me/)
passport-0.5.0/lib/ 0000775 0000000 0000000 00000000000 14123202540 0014126 5 ustar 00root root 0000000 0000000 passport-0.5.0/lib/authenticator.js 0000664 0000000 0000000 00000032060 14123202540 0017337 0 ustar 00root root 0000000 0000000 /**
* Module dependencies.
*/
var SessionStrategy = require('./strategies/session')
, SessionManager = require('./sessionmanager');
/**
* `Authenticator` constructor.
*
* @api public
*/
function Authenticator() {
this._key = 'passport';
this._strategies = {};
this._serializers = [];
this._deserializers = [];
this._infoTransformers = [];
this._framework = null;
this.init();
}
/**
* Initialize authenticator.
*
* @api protected
*/
Authenticator.prototype.init = function() {
this.framework(require('./framework/connect')());
this.use(new SessionStrategy({ key: this._key }, this.deserializeUser.bind(this)));
this._sm = new SessionManager({ key: this._key }, this.serializeUser.bind(this));
};
/**
* Utilize the given `strategy` with optional `name`, overridding the strategy's
* default name.
*
* Examples:
*
* passport.use(new TwitterStrategy(...));
*
* passport.use('api', new http.BasicStrategy(...));
*
* @param {String|Strategy} name
* @param {Strategy} strategy
* @return {Authenticator} for chaining
* @api public
*/
Authenticator.prototype.use = function(name, strategy) {
if (!strategy) {
strategy = name;
name = strategy.name;
}
if (!name) { throw new Error('Authentication strategies must have a name'); }
this._strategies[name] = strategy;
return this;
};
/**
* Un-utilize the `strategy` with given `name`.
*
* In typical applications, the necessary authentication strategies are static,
* configured once and always available. As such, there is often no need to
* invoke this function.
*
* However, in certain situations, applications may need dynamically configure
* and de-configure authentication strategies. The `use()`/`unuse()`
* combination satisfies these scenarios.
*
* Examples:
*
* passport.unuse('legacy-api');
*
* @param {String} name
* @return {Authenticator} for chaining
* @api public
*/
Authenticator.prototype.unuse = function(name) {
delete this._strategies[name];
return this;
};
/**
* Setup Passport to be used under framework.
*
* By default, Passport exposes middleware that operate using Connect-style
* middleware using a `fn(req, res, next)` signature. Other popular frameworks
* have different expectations, and this function allows Passport to be adapted
* to operate within such environments.
*
* If you are using a Connect-compatible framework, including Express, there is
* no need to invoke this function.
*
* Examples:
*
* passport.framework(require('hapi-passport')());
*
* @param {Object} name
* @return {Authenticator} for chaining
* @api public
*/
Authenticator.prototype.framework = function(fw) {
this._framework = fw;
return this;
};
/**
* Passport's primary initialization middleware.
*
* This middleware must be in use by the Connect/Express application for
* Passport to operate.
*
* Options:
* - `userProperty` Property to set on `req` upon login, defaults to _user_
*
* Examples:
*
* app.use(passport.initialize());
*
* app.use(passport.initialize({ userProperty: 'currentUser' }));
*
* @param {Object} options
* @return {Function} middleware
* @api public
*/
Authenticator.prototype.initialize = function(options) {
options = options || {};
return this._framework.initialize(this, options);
};
/**
* Middleware that will authenticate a request using the given `strategy` name,
* with optional `options` and `callback`.
*
* Examples:
*
* passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' })(req, res);
*
* passport.authenticate('local', function(err, user) {
* if (!user) { return res.redirect('/login'); }
* res.end('Authenticated!');
* })(req, res);
*
* passport.authenticate('basic', { session: false })(req, res);
*
* app.get('/auth/twitter', passport.authenticate('twitter'), function(req, res) {
* // request will be redirected to Twitter
* });
* app.get('/auth/twitter/callback', passport.authenticate('twitter'), function(req, res) {
* res.json(req.user);
* });
*
* @param {String} strategy
* @param {Object} options
* @param {Function} callback
* @return {Function} middleware
* @api public
*/
Authenticator.prototype.authenticate = function(strategy, options, callback) {
return this._framework.authenticate(this, strategy, options, callback);
};
/**
* Middleware that will authorize a third-party account using the given
* `strategy` name, with optional `options`.
*
* If authorization is successful, the result provided by the strategy's verify
* callback will be assigned to `req.account`. The existing login session and
* `req.user` will be unaffected.
*
* This function is particularly useful when connecting third-party accounts
* to the local account of a user that is currently authenticated.
*
* Examples:
*
* passport.authorize('twitter-authz', { failureRedirect: '/account' });
*
* @param {String} strategy
* @param {Object} options
* @return {Function} middleware
* @api public
*/
Authenticator.prototype.authorize = function(strategy, options, callback) {
options = options || {};
options.assignProperty = 'account';
var fn = this._framework.authorize || this._framework.authenticate;
return fn(this, strategy, options, callback);
};
/**
* Middleware that will restore login state from a session.
*
* Web applications typically use sessions to maintain login state between
* requests. For example, a user will authenticate by entering credentials into
* a form which is submitted to the server. If the credentials are valid, a
* login session is established by setting a cookie containing a session
* identifier in the user's web browser. The web browser will send this cookie
* in subsequent requests to the server, allowing a session to be maintained.
*
* If sessions are being utilized, and a login session has been established,
* this middleware will populate `req.user` with the current user.
*
* Note that sessions are not strictly required for Passport to operate.
* However, as a general rule, most web applications will make use of sessions.
* An exception to this rule would be an API server, which expects each HTTP
* request to provide credentials in an Authorization header.
*
* Examples:
*
* app.use(connect.cookieParser());
* app.use(connect.session({ secret: 'keyboard cat' }));
* app.use(passport.initialize());
* app.use(passport.session());
*
* Options:
* - `pauseStream` Pause the request stream before deserializing the user
* object from the session. Defaults to _false_. Should
* be set to true in cases where middleware consuming the
* request body is configured after passport and the
* deserializeUser method is asynchronous.
*
* @param {Object} options
* @return {Function} middleware
* @api public
*/
Authenticator.prototype.session = function(options) {
return this.authenticate('session', options);
};
// TODO: Make session manager pluggable
/*
Authenticator.prototype.sessionManager = function(mgr) {
this._sm = mgr;
return this;
}
*/
/**
* Registers a function used to serialize user objects into the session.
*
* Examples:
*
* passport.serializeUser(function(user, done) {
* done(null, user.id);
* });
*
* @api public
*/
Authenticator.prototype.serializeUser = function(fn, req, done) {
if (typeof fn === 'function') {
return this._serializers.push(fn);
}
// private implementation that traverses the chain of serializers, attempting
// to serialize a user
var user = fn;
// For backwards compatibility
if (typeof req === 'function') {
done = req;
req = undefined;
}
var stack = this._serializers;
(function pass(i, err, obj) {
// serializers use 'pass' as an error to skip processing
if ('pass' === err) {
err = undefined;
}
// an error or serialized object was obtained, done
if (err || obj || obj === 0) { return done(err, obj); }
var layer = stack[i];
if (!layer) {
return done(new Error('Failed to serialize user into session'));
}
function serialized(e, o) {
pass(i + 1, e, o);
}
try {
var arity = layer.length;
if (arity == 3) {
layer(req, user, serialized);
} else {
layer(user, serialized);
}
} catch(e) {
return done(e);
}
})(0);
};
/**
* Registers a function used to deserialize user objects out of the session.
*
* Examples:
*
* passport.deserializeUser(function(id, done) {
* User.findById(id, function (err, user) {
* done(err, user);
* });
* });
*
* @api public
*/
Authenticator.prototype.deserializeUser = function(fn, req, done) {
if (typeof fn === 'function') {
return this._deserializers.push(fn);
}
// private implementation that traverses the chain of deserializers,
// attempting to deserialize a user
var obj = fn;
// For backwards compatibility
if (typeof req === 'function') {
done = req;
req = undefined;
}
var stack = this._deserializers;
(function pass(i, err, user) {
// deserializers use 'pass' as an error to skip processing
if ('pass' === err) {
err = undefined;
}
// an error or deserialized user was obtained, done
if (err || user) { return done(err, user); }
// a valid user existed when establishing the session, but that user has
// since been removed
if (user === null || user === false) { return done(null, false); }
var layer = stack[i];
if (!layer) {
return done(new Error('Failed to deserialize user out of session'));
}
function deserialized(e, u) {
pass(i + 1, e, u);
}
try {
var arity = layer.length;
if (arity == 3) {
layer(req, obj, deserialized);
} else {
layer(obj, deserialized);
}
} catch(e) {
return done(e);
}
})(0);
};
/**
* Registers a function used to transform auth info.
*
* In some circumstances authorization details are contained in authentication
* credentials or loaded as part of verification.
*
* For example, when using bearer tokens for API authentication, the tokens may
* encode (either directly or indirectly in a database), details such as scope
* of access or the client to which the token was issued.
*
* Such authorization details should be enforced separately from authentication.
* Because Passport deals only with the latter, this is the responsiblity of
* middleware or routes further along the chain. However, it is not optimal to
* decode the same data or execute the same database query later. To avoid
* this, Passport accepts optional `info` along with the authenticated `user`
* in a strategy's `success()` action. This info is set at `req.authInfo`,
* where said later middlware or routes can access it.
*
* Optionally, applications can register transforms to proccess this info,
* which take effect prior to `req.authInfo` being set. This is useful, for
* example, when the info contains a client ID. The transform can load the
* client from the database and include the instance in the transformed info,
* allowing the full set of client properties to be convieniently accessed.
*
* If no transforms are registered, `info` supplied by the strategy will be left
* unmodified.
*
* Examples:
*
* passport.transformAuthInfo(function(info, done) {
* Client.findById(info.clientID, function (err, client) {
* info.client = client;
* done(err, info);
* });
* });
*
* @api public
*/
Authenticator.prototype.transformAuthInfo = function(fn, req, done) {
if (typeof fn === 'function') {
return this._infoTransformers.push(fn);
}
// private implementation that traverses the chain of transformers,
// attempting to transform auth info
var info = fn;
// For backwards compatibility
if (typeof req === 'function') {
done = req;
req = undefined;
}
var stack = this._infoTransformers;
(function pass(i, err, tinfo) {
// transformers use 'pass' as an error to skip processing
if ('pass' === err) {
err = undefined;
}
// an error or transformed info was obtained, done
if (err || tinfo) { return done(err, tinfo); }
var layer = stack[i];
if (!layer) {
// if no transformers are registered (or they all pass), the default
// behavior is to use the un-transformed info as-is
return done(null, info);
}
function transformed(e, t) {
pass(i + 1, e, t);
}
try {
var arity = layer.length;
if (arity == 1) {
// sync
var t = layer(info);
transformed(null, t);
} else if (arity == 3) {
layer(req, info, transformed);
} else {
layer(info, transformed);
}
} catch(e) {
return done(e);
}
})(0);
};
/**
* Return strategy with given `name`.
*
* @param {String} name
* @return {Strategy}
* @api private
*/
Authenticator.prototype._strategy = function(name) {
return this._strategies[name];
};
/**
* Expose `Authenticator`.
*/
module.exports = Authenticator;
passport-0.5.0/lib/errors/ 0000775 0000000 0000000 00000000000 14123202540 0015442 5 ustar 00root root 0000000 0000000 passport-0.5.0/lib/errors/authenticationerror.js 0000664 0000000 0000000 00000000666 14123202540 0022101 0 ustar 00root root 0000000 0000000 /**
* `AuthenticationError` error.
*
* @constructor
* @api private
*/
function AuthenticationError(message, status) {
Error.call(this);
Error.captureStackTrace(this, arguments.callee);
this.name = 'AuthenticationError';
this.message = message;
this.status = status || 401;
}
// Inherit from `Error`.
AuthenticationError.prototype.__proto__ = Error.prototype;
// Expose constructor.
module.exports = AuthenticationError;
passport-0.5.0/lib/framework/ 0000775 0000000 0000000 00000000000 14123202540 0016123 5 ustar 00root root 0000000 0000000 passport-0.5.0/lib/framework/connect.js 0000664 0000000 0000000 00000000770 14123202540 0020116 0 ustar 00root root 0000000 0000000 /**
* Module dependencies.
*/
var initialize = require('../middleware/initialize')
, authenticate = require('../middleware/authenticate');
/**
* Framework support for Connect/Express.
*
* This module provides support for using Passport with Express. It exposes
* middleware that conform to the `fn(req, res, next)` signature.
*
* @return {Object}
* @api protected
*/
exports = module.exports = function() {
return {
initialize: initialize,
authenticate: authenticate
};
};
passport-0.5.0/lib/http/ 0000775 0000000 0000000 00000000000 14123202540 0015105 5 ustar 00root root 0000000 0000000 passport-0.5.0/lib/http/request.js 0000664 0000000 0000000 00000003415 14123202540 0017136 0 ustar 00root root 0000000 0000000 var req = exports = module.exports = {};
/**
* Initiate a login session for `user`.
*
* Options:
* - `session` Save login state in session, defaults to _true_
*
* Examples:
*
* req.logIn(user, { session: false });
*
* req.logIn(user, function(err) {
* if (err) { throw err; }
* // session saved
* });
*
* @param {User} user
* @param {Object} options
* @param {Function} done
* @api public
*/
req.login =
req.logIn = function(user, options, done) {
if (typeof options == 'function') {
done = options;
options = {};
}
options = options || {};
var property = this._userProperty || 'user';
var session = (options.session === undefined) ? true : options.session;
this[property] = user;
if (session) {
if (!this._passport) { throw new Error('passport.initialize() middleware not in use'); }
if (typeof done != 'function') { throw new Error('req#login requires a callback function'); }
var self = this;
this._passport.instance._sm.logIn(this, user, function(err) {
if (err) { self[property] = null; return done(err); }
done();
});
} else {
done && done();
}
};
/**
* Terminate an existing login session.
*
* @api public
*/
req.logout =
req.logOut = function() {
var property = this._userProperty || 'user';
this[property] = null;
if (this._passport) {
this._passport.instance._sm.logOut(this);
}
};
/**
* Test if request is authenticated.
*
* @return {Boolean}
* @api public
*/
req.isAuthenticated = function() {
var property = this._userProperty || 'user';
return (this[property]) ? true : false;
};
/**
* Test if request is unauthenticated.
*
* @return {Boolean}
* @api public
*/
req.isUnauthenticated = function() {
return !this.isAuthenticated();
};
passport-0.5.0/lib/index.js 0000664 0000000 0000000 00000000732 14123202540 0015575 0 ustar 00root root 0000000 0000000 /**
* Module dependencies.
*/
var Passport = require('./authenticator')
, SessionStrategy = require('./strategies/session');
/**
* Export default singleton.
*
* @api public
*/
exports = module.exports = new Passport();
/**
* Expose constructors.
*/
exports.Passport =
exports.Authenticator = Passport;
exports.Strategy = require('passport-strategy');
/**
* Expose strategies.
*/
exports.strategies = {};
exports.strategies.SessionStrategy = SessionStrategy;
passport-0.5.0/lib/middleware/ 0000775 0000000 0000000 00000000000 14123202540 0016243 5 ustar 00root root 0000000 0000000 passport-0.5.0/lib/middleware/authenticate.js 0000664 0000000 0000000 00000032242 14123202540 0021262 0 ustar 00root root 0000000 0000000 /**
* Module dependencies.
*/
var http = require('http')
, IncomingMessageExt = require('../http/request')
, AuthenticationError = require('../errors/authenticationerror');
/**
* Authenticates requests.
*
* Applies the `name`ed strategy (or strategies) to the incoming request, in
* order to authenticate the request. If authentication is successful, the user
* will be logged in and populated at `req.user` and a session will be
* established by default. If authentication fails, an unauthorized response
* will be sent.
*
* Options:
* - `session` Save login state in session, defaults to _true_
* - `successRedirect` After successful login, redirect to given URL
* - `successMessage` True to store success message in
* req.session.messages, or a string to use as override
* message for success.
* - `successFlash` True to flash success messages or a string to use as a flash
* message for success (overrides any from the strategy itself).
* - `failureRedirect` After failed login, redirect to given URL
* - `failureMessage` True to store failure message in
* req.session.messages, or a string to use as override
* message for failure.
* - `failureFlash` True to flash failure messages or a string to use as a flash
* message for failures (overrides any from the strategy itself).
* - `assignProperty` Assign the object provided by the verify callback to given property
*
* An optional `callback` can be supplied to allow the application to override
* the default manner in which authentication attempts are handled. The
* callback has the following signature, where `user` will be set to the
* authenticated user on a successful authentication attempt, or `false`
* otherwise. An optional `info` argument will be passed, containing additional
* details provided by the strategy's verify callback - this could be information about
* a successful authentication or a challenge message for a failed authentication.
* An optional `status` argument will be passed when authentication fails - this could
* be a HTTP response code for a remote authentication failure or similar.
*
* app.get('/protected', function(req, res, next) {
* passport.authenticate('local', function(err, user, info, status) {
* if (err) { return next(err) }
* if (!user) { return res.redirect('/signin') }
* res.redirect('/account');
* })(req, res, next);
* });
*
* Note that if a callback is supplied, it becomes the application's
* responsibility to log-in the user, establish a session, and otherwise perform
* the desired operations.
*
* Examples:
*
* passport.authenticate('local', { successRedirect: '/', failureRedirect: '/login' });
*
* passport.authenticate('basic', { session: false });
*
* passport.authenticate('twitter');
*
* @param {Strategy|String|Array} name
* @param {Object} options
* @param {Function} callback
* @return {Function}
* @api public
*/
module.exports = function authenticate(passport, name, options, callback) {
if (typeof options == 'function') {
callback = options;
options = {};
}
options = options || {};
var multi = true;
// Cast `name` to an array, allowing authentication to pass through a chain of
// strategies. The first strategy to succeed, redirect, or error will halt
// the chain. Authentication failures will proceed through each strategy in
// series, ultimately failing if all strategies fail.
//
// This is typically used on API endpoints to allow clients to authenticate
// using their preferred choice of Basic, Digest, token-based schemes, etc.
// It is not feasible to construct a chain of multiple strategies that involve
// redirection (for example both Facebook and Twitter), since the first one to
// redirect will halt the chain.
if (!Array.isArray(name)) {
name = [ name ];
multi = false;
}
return function authenticate(req, res, next) {
// accumulator for failures from each strategy in the chain
var failures = [];
function allFailed() {
if (callback) {
if (!multi) {
return callback(null, false, failures[0].challenge, failures[0].status);
} else {
var challenges = failures.map(function(f) { return f.challenge; });
var statuses = failures.map(function(f) { return f.status; });
return callback(null, false, challenges, statuses);
}
}
// Strategies are ordered by priority. For the purpose of flashing a
// message, the first failure will be displayed.
var failure = failures[0] || {}
, challenge = failure.challenge || {}
, msg;
if (options.failureFlash) {
var flash = options.failureFlash;
if (typeof flash == 'string') {
flash = { type: 'error', message: flash };
}
flash.type = flash.type || 'error';
var type = flash.type || challenge.type || 'error';
msg = flash.message || challenge.message || challenge;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.failureMessage) {
msg = options.failureMessage;
if (typeof msg == 'boolean') {
msg = challenge.message || challenge;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.failureRedirect) {
return res.redirect(options.failureRedirect);
}
// When failure handling is not delegated to the application, the default
// is to respond with 401 Unauthorized. Note that the WWW-Authenticate
// header will be set according to the strategies in use (see
// actions#fail). If multiple strategies failed, each of their challenges
// will be included in the response.
var rchallenge = []
, rstatus, status;
for (var j = 0, len = failures.length; j < len; j++) {
failure = failures[j];
challenge = failure.challenge;
status = failure.status;
rstatus = rstatus || status;
if (typeof challenge == 'string') {
rchallenge.push(challenge);
}
}
res.statusCode = rstatus || 401;
if (res.statusCode == 401 && rchallenge.length) {
res.setHeader('WWW-Authenticate', rchallenge);
}
if (options.failWithError) {
return next(new AuthenticationError(http.STATUS_CODES[res.statusCode], rstatus));
}
res.end(http.STATUS_CODES[res.statusCode]);
}
(function attempt(i) {
var layer = name[i];
// If no more strategies exist in the chain, authentication has failed.
if (!layer) { return allFailed(); }
// Get the strategy, which will be used as prototype from which to create
// a new instance. Action functions will then be bound to the strategy
// within the context of the HTTP request/response pair.
var strategy, prototype;
if (typeof layer.authenticate == 'function') {
strategy = layer;
} else {
prototype = passport._strategy(layer);
if (!prototype) { return next(new Error('Unknown authentication strategy "' + layer + '"')); }
strategy = Object.create(prototype);
}
// ----- BEGIN STRATEGY AUGMENTATION -----
// Augment the new strategy instance with action functions. These action
// functions are bound via closure the the request/response pair. The end
// goal of the strategy is to invoke *one* of these action methods, in
// order to indicate successful or failed authentication, redirect to a
// third-party identity provider, etc.
/**
* Authenticate `user`, with optional `info`.
*
* Strategies should call this function to successfully authenticate a
* user. `user` should be an object supplied by the application after it
* has been given an opportunity to verify credentials. `info` is an
* optional argument containing additional user information. This is
* useful for third-party authentication strategies to pass profile
* details.
*
* @param {Object} user
* @param {Object} info
* @api public
*/
strategy.success = function(user, info) {
if (callback) {
return callback(null, user, info);
}
info = info || {};
var msg;
if (options.successFlash) {
var flash = options.successFlash;
if (typeof flash == 'string') {
flash = { type: 'success', message: flash };
}
flash.type = flash.type || 'success';
var type = flash.type || info.type || 'success';
msg = flash.message || info.message || info;
if (typeof msg == 'string') {
req.flash(type, msg);
}
}
if (options.successMessage) {
msg = options.successMessage;
if (typeof msg == 'boolean') {
msg = info.message || info;
}
if (typeof msg == 'string') {
req.session.messages = req.session.messages || [];
req.session.messages.push(msg);
}
}
if (options.assignProperty) {
req[options.assignProperty] = user;
return next();
}
req.logIn(user, options, function(err) {
if (err) { return next(err); }
function complete() {
if (options.successReturnToOrRedirect) {
var url = options.successReturnToOrRedirect;
if (req.session && req.session.returnTo) {
url = req.session.returnTo;
delete req.session.returnTo;
}
return res.redirect(url);
}
if (options.successRedirect) {
return res.redirect(options.successRedirect);
}
next();
}
if (options.authInfo !== false) {
passport.transformAuthInfo(info, req, function(err, tinfo) {
if (err) { return next(err); }
req.authInfo = tinfo;
complete();
});
} else {
complete();
}
});
};
/**
* Fail authentication, with optional `challenge` and `status`, defaulting
* to 401.
*
* Strategies should call this function to fail an authentication attempt.
*
* @param {String} challenge
* @param {Number} status
* @api public
*/
strategy.fail = function(challenge, status) {
if (typeof challenge == 'number') {
status = challenge;
challenge = undefined;
}
// push this failure into the accumulator and attempt authentication
// using the next strategy
failures.push({ challenge: challenge, status: status });
attempt(i + 1);
};
/**
* Redirect to `url` with optional `status`, defaulting to 302.
*
* Strategies should call this function to redirect the user (via their
* user agent) to a third-party website for authentication.
*
* @param {String} url
* @param {Number} status
* @api public
*/
strategy.redirect = function(url, status) {
// NOTE: Do not use `res.redirect` from Express, because it can't decide
// what it wants.
//
// Express 2.x: res.redirect(url, status)
// Express 3.x: res.redirect(status, url) -OR- res.redirect(url, status)
// - as of 3.14.0, deprecated warnings are issued if res.redirect(url, status)
// is used
// Express 4.x: res.redirect(status, url)
// - all versions (as of 4.8.7) continue to accept res.redirect(url, status)
// but issue deprecated versions
res.statusCode = status || 302;
res.setHeader('Location', url);
res.setHeader('Content-Length', '0');
res.end();
};
/**
* Pass without making a success or fail decision.
*
* Under most circumstances, Strategies should not need to call this
* function. It exists primarily to allow previous authentication state
* to be restored, for example from an HTTP session.
*
* @api public
*/
strategy.pass = function() {
next();
};
/**
* Internal error while performing authentication.
*
* Strategies should call this function when an internal error occurs
* during the process of performing authentication; for example, if the
* user directory is not available.
*
* @param {Error} err
* @api public
*/
strategy.error = function(err) {
if (callback) {
return callback(err);
}
next(err);
};
// ----- END STRATEGY AUGMENTATION -----
strategy.authenticate(req, options);
})(0); // attempt
};
};
passport-0.5.0/lib/middleware/initialize.js 0000664 0000000 0000000 00000004142 14123202540 0020743 0 ustar 00root root 0000000 0000000 /**
* Module dependencies.
*/
var IncomingMessageExt = require('../http/request');
/**
* Passport initialization.
*
* Intializes Passport for incoming requests, allowing authentication strategies
* to be applied.
*
* If sessions are being utilized, applications must set up Passport with
* functions to serialize a user into and out of a session. For example, a
* common pattern is to serialize just the user ID into the session (due to the
* fact that it is desirable to store the minimum amount of data in a session).
* When a subsequent request arrives for the session, the full User object can
* be loaded from the database by ID.
*
* Note that additional middleware is required to persist login state, so we
* must use the `connect.session()` middleware _before_ `passport.initialize()`.
*
* If sessions are being used, this middleware must be in use by the
* Connect/Express application for Passport to operate. If the application is
* entirely stateless (not using sessions), this middleware is not necessary,
* but its use will not have any adverse impact.
*
* Examples:
*
* app.use(connect.cookieParser());
* app.use(connect.session({ secret: 'keyboard cat' }));
* app.use(passport.initialize());
* app.use(passport.session());
*
* passport.serializeUser(function(user, done) {
* done(null, user.id);
* });
*
* passport.deserializeUser(function(id, done) {
* User.findById(id, function (err, user) {
* done(err, user);
* });
* });
*
* @return {Function}
* @api public
*/
module.exports = function initialize(passport, options) {
options = options || {};
return function initialize(req, res, next) {
req.login =
req.logIn = IncomingMessageExt.logIn;
req.logout =
req.logOut = IncomingMessageExt.logOut;
req.isAuthenticated = IncomingMessageExt.isAuthenticated;
req.isUnauthenticated = IncomingMessageExt.isUnauthenticated;
if (options.userProperty) {
req._userProperty = options.userProperty;
}
req._passport = {};
req._passport.instance = passport;
next();
};
};
passport-0.5.0/lib/sessionmanager.js 0000664 0000000 0000000 00000001551 14123202540 0017504 0 ustar 00root root 0000000 0000000 function SessionManager(options, serializeUser) {
if (typeof options == 'function') {
serializeUser = options;
options = undefined;
}
options = options || {};
this._key = options.key || 'passport';
this._serializeUser = serializeUser;
}
SessionManager.prototype.logIn = function(req, user, cb) {
var self = this;
this._serializeUser(user, req, function(err, obj) {
if (err) {
return cb(err);
}
// TODO: Error if session isn't available here.
if (!req.session) {
req.session = {};
}
if (!req.session[self._key]) {
req.session[self._key] = {};
}
req.session[self._key].user = obj;
cb();
});
}
SessionManager.prototype.logOut = function(req, cb) {
if (req.session && req.session[this._key]) {
delete req.session[this._key].user;
}
cb && cb();
}
module.exports = SessionManager;
passport-0.5.0/lib/strategies/ 0000775 0000000 0000000 00000000000 14123202540 0016300 5 ustar 00root root 0000000 0000000 passport-0.5.0/lib/strategies/session.js 0000664 0000000 0000000 00000004034 14123202540 0020322 0 ustar 00root root 0000000 0000000 /**
* Module dependencies.
*/
var pause = require('pause')
, util = require('util')
, Strategy = require('passport-strategy');
/**
* `SessionStrategy` constructor.
*
* @api public
*/
function SessionStrategy(options, deserializeUser) {
if (typeof options == 'function') {
deserializeUser = options;
options = undefined;
}
options = options || {};
Strategy.call(this);
this.name = 'session';
this._key = options.key || 'passport';
this._deserializeUser = deserializeUser;
}
/**
* Inherit from `Strategy`.
*/
util.inherits(SessionStrategy, Strategy);
/**
* Authenticate request based on the current session state.
*
* The session authentication strategy uses the session to restore any login
* state across requests. If a login session has been established, `req.user`
* will be populated with the current user.
*
* This strategy is registered automatically by Passport.
*
* @param {Object} req
* @param {Object} options
* @api protected
*/
SessionStrategy.prototype.authenticate = function(req, options) {
if (!req._passport) { return this.error(new Error('passport.initialize() middleware not in use')); }
options = options || {};
var self = this,
su;
if (req.session[this._key]) {
su = req.session[this._key].user;
}
if (su || su === 0) {
// NOTE: Stream pausing is desirable in the case where later middleware is
// listening for events emitted from request. For discussion on the
// matter, refer to: https://github.com/jaredhanson/passport/pull/106
var paused = options.pauseStream ? pause(req) : null;
this._deserializeUser(su, req, function(err, user) {
if (err) { return self.error(err); }
if (!user) {
delete req.session[self._key].user;
} else {
var property = req._userProperty || 'user';
req[property] = user;
}
self.pass();
if (paused) {
paused.resume();
}
});
} else {
self.pass();
}
};
/**
* Expose `SessionStrategy`.
*/
module.exports = SessionStrategy;
passport-0.5.0/package.json 0000664 0000000 0000000 00000002343 14123202540 0015650 0 ustar 00root root 0000000 0000000 {
"name": "passport",
"version": "0.5.0",
"description": "Simple, unobtrusive authentication for Node.js.",
"keywords": [
"express",
"connect",
"auth",
"authn",
"authentication"
],
"author": {
"name": "Jared Hanson",
"email": "jaredhanson@gmail.com",
"url": "http://www.jaredhanson.net/"
},
"homepage": "http://passportjs.org/",
"repository": {
"type": "git",
"url": "git://github.com/jaredhanson/passport.git"
},
"bugs": {
"url": "http://github.com/jaredhanson/passport/issues"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/jaredhanson"
},
"license": "MIT",
"licenses": [
{
"type": "MIT",
"url": "http://opensource.org/licenses/MIT"
}
],
"main": "./lib",
"dependencies": {
"passport-strategy": "1.x.x",
"pause": "0.0.1"
},
"devDependencies": {
"make-node": "0.3.x",
"mocha": "2.x.x",
"chai": "2.x.x",
"chai-connect-middleware": "0.3.x",
"chai-passport-strategy": "0.2.x",
"proxyquire": "1.4.x"
},
"engines": {
"node": ">= 0.4.0"
},
"scripts": {
"test": "node_modules/.bin/mocha --reporter spec --require test/bootstrap/node test/*.test.js test/**/*.test.js"
}
}
passport-0.5.0/sponsors/ 0000775 0000000 0000000 00000000000 14123202540 0015246 5 ustar 00root root 0000000 0000000 passport-0.5.0/sponsors/loginradius.png 0000664 0000000 0000000 00000025210 14123202540 0020274 0 ustar 00root root 0000000 0000000 PNG
IHDR 2 B. sRGB pHYs #iTXtXML:com.adobe.xmp
2
0
72
1
72
243
1
50
2020-12-11T11:12:93
Pixelmator 3.9
o %IDATx} ŝ]3 aP9:jĿfn\k52
+ D#Ѩ@\`8BaPfޛ~^B^Mw__ZPgV!}̾$2vOH9~[H-}@>|c bIaN]_$D"{7iF44m;?Eh϶,3
NB&A2U5t1yyh?1OzV:tq
Jyp
Tĭ>
=FثtݨSc.|l}ЦIޖ{&lXj\Byh1߷Z-~%=OnpTфK0BzXj4[\U[shVsyR?XUф|_lBՊPVmvPiʪ$r/D.@PD|ALԹ<ִ.0]FL6hCqVt(%^wRYU :Hl ٌbI4&Y5R
MI-l">G|
6ב-AJG#=N!<881^9!rKvKOl6ck נ?3vy+8kO"i~#]%rFݱ|7l
U%`>"cy[ s,Y4[Vt'tRRs06oSkuπ~g d@BzFFr[#N~IXLU"K
s_A]dEV=Bq#[٘.wL¶7-M<4Ar
^~ӑŋܴ#}{P 6c/I?ߩ7IY ׯ6U4m3[y/쥦 khG$1EwAɁiA_u?G[E31mnv4/~궴 X
/zHA&ifXCb2ձhgu:!sSn-gܑ6eRjIQZ [08óR6oXkA/[TnrD (GH%MQRh+?uZ!,t&Lb&^2p2EȱjqsPڦi#9J-km>XAa|;
K֜>+rXq|e4/iCR$&i[_ڨT\Wj`檱 ;2ScyNQZ*j-kKÒ;TMVS x;N$g xFLM<ƞ5nô7Pc
K7#剹CaѪ`iŝ婂 /7KVRdKJf3 1,~}?Fuzp`cB+!1* Y9?m<ufдVK| #ZJI`&NsҞ1"{4m[8F};R_[5ܲœaY/Iɼc
3$ /?Yяg_OՃ1)Dt`2 kЀ E{$zKP5~6nOEfJ{cy2a>o_xdɤibY
ee>H_jP*v^k'u'Tq]J;"i2b3۞5ьقiRn _Qo^G[@>[5`>&M*%S(WQo2{icXÀC>ƤnkLŖ'M7%%kYU hthΩ) ܇qa
W^b
@<58sfA_% /is SqJK[Il )X!@@'f0987f@xYzNpF1b2cѧ2
Z>,CkW5KB%'#ut 4u 9X]C8<Ky) dfO7+ҏ &*$[6gb.,hSaW8K-ۤO~oãPv[
tK)jh7)d!#,4~$;KKweZs
30.U-\F*osX8ej'b.빃s8X;մ%7չ.?>jmmYe(P2Ѝ:W?
$lmLPo~جPe2ϕc-hvT㯤@d W/j}GuӰf"̝/KW]jx|8a6&N%ILJ3Hs3чl3kPd`gPF?(GwT63MllyA$a*?⤅KO&,0`GKRxbhFirM/[`w-) k0hN ,괥".OJ+*L)A^0"@Ը{};1Eƭȁ6`N7Ո{ f 48:Kn"㮸Nu@o<ϳbv+3Y c.
-p+Nb1p 3"{=ٴd^|^gIbÒ-sgZhMr38\h V
U
Opg\Wlgǿ3iq)s:.ĵd+9 7 o(iVQ'sO8yяi-~,C6ˏ=Q+D䛎bcO)i[fͅ`[:i.m&ܜkFX_2~00&\H r~!nS8/peUQ ]ButꅃcP(onj:T<vҍbH=n,K]pU%rx9/
A!NELStY؎a:'Z`+è>!fE.Z8|mSyю&F
P.'TtoHKoY
%tm#kDۥߖcI̶`R1^w=YѓStC5G/ŊsEӭjfjLWbw wvI{f[R]i N^07vx:k7d|UB;9b^A"0fj!
k,,B?(*F?gIYkS{-=e٫ߥ)U7> v}rmsŻ2໔V~$xI%)(]T1eCm}
%%q`FcFʏ/$WJ*O5qTiU&@~7Am?lGbn/lhu`Xb
bp4@0|RHf<$CUQ/Z+1K0/ZR8Qs sLH'+.TrEjM[(a^Lʜ[j.,<"E:ܬx=
8p4c'Xsc\JU^쀶*dgaG#B/čI^u.!Vq>%((39Re|=4XAx4q)Yqz"MhC)Ӝpcm3uR~
b#RC9L&d v
:ē
3!:vp
_|JXƙN,<;%([yRqh*#ʓN3X K='XZ0o) 7AX{저߇bj31~IqQ:RcAUT6"`~dvjUL2ϡ-7ɯZn1&)݆>F@xe9K,%ck pJf<w(T,_vIBX ºczJg`487`'Y$j6fHtbVo)%oGLm8VMH'&:h=+rfOm\O89?9sQvڂH'snN,,*нp=dXEf<sǽ9aW07~$\-]{ڏ3qǷBvP0ש:)$"Ω4jfI>!