Made all login Patreon only, limited some functionality to $5 patrons
This commit is contained in:
1
app/packages/accounts-patreon/.gitignore
vendored
Normal file
1
app/packages/accounts-patreon/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
.build*
|
||||
17
app/packages/accounts-patreon/package.js
Normal file
17
app/packages/accounts-patreon/package.js
Normal file
@@ -0,0 +1,17 @@
|
||||
Package.describe({
|
||||
summary: 'Login service for Patreon accounts',
|
||||
version: '0.1.0',
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
api.use('ecmascript');
|
||||
api.use('accounts-base', ['client', 'server']);
|
||||
// Export Accounts (etc) to packages using this one.
|
||||
api.imply('accounts-base', ['client', 'server']);
|
||||
|
||||
api.use('accounts-oauth', ['client', 'server']);
|
||||
api.use('patreon-oauth');
|
||||
api.imply('patreon-oauth');
|
||||
|
||||
api.addFiles('patreon.js');
|
||||
});
|
||||
26
app/packages/accounts-patreon/patreon.js
Normal file
26
app/packages/accounts-patreon/patreon.js
Normal file
@@ -0,0 +1,26 @@
|
||||
Accounts.oauth.registerService('patreon');
|
||||
console.log('accounts-patreon');
|
||||
|
||||
if (Meteor.isClient) {
|
||||
const loginWithPatreon = (options, callback) => {
|
||||
// support a callback without options
|
||||
if (! callback && typeof options === 'function') {
|
||||
callback = options;
|
||||
options = null;
|
||||
}
|
||||
|
||||
const credentialRequestCompleteCallback = Accounts.oauth.credentialRequestCompleteHandler(callback);
|
||||
Patreon.requestCredential(options, credentialRequestCompleteCallback);
|
||||
};
|
||||
Accounts.registerClientLoginFunction('patreon', loginWithPatreon);
|
||||
Meteor.loginWithPatreon =
|
||||
(...args) => Accounts.applyLoginFunction('patreon', args);
|
||||
} else {
|
||||
Accounts.addAutopublishFields({
|
||||
// publish all fields including access token, which can legitimately
|
||||
// be used from the client (if transmitted over ssl or on
|
||||
// localhost). http://www.meetup.com/meetup_api/auth/#oauth2implicit
|
||||
forLoggedInUser: ['services.patreon'],
|
||||
forOtherUsers: ['services.patreon.id']
|
||||
});
|
||||
}
|
||||
3
app/packages/patreon-oauth/README.md
Normal file
3
app/packages/patreon-oauth/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# patreon-oauth
|
||||
|
||||
An implementation of the Patreon OAuth flow. See the [Meteor Guide](https://guide.meteor.com/accounts.html) for more details.
|
||||
18
app/packages/patreon-oauth/package.js
Normal file
18
app/packages/patreon-oauth/package.js
Normal file
@@ -0,0 +1,18 @@
|
||||
Package.describe({
|
||||
summary: 'Patreon OAuth flow',
|
||||
version: '0.1.0'
|
||||
});
|
||||
|
||||
Package.onUse(api => {
|
||||
api.use('ecmascript');
|
||||
api.use('oauth2', ['client', 'server']);
|
||||
api.use('oauth', ['client', 'server']);
|
||||
api.use('http', 'server');
|
||||
api.use('random', 'client');
|
||||
api.use('service-configuration', ['client', 'server']);
|
||||
|
||||
api.addFiles('patreon_server.js', 'server');
|
||||
api.addFiles('patreon_client.js', 'client');
|
||||
|
||||
api.export('Patreon');
|
||||
});
|
||||
54
app/packages/patreon-oauth/patreon_client.js
Normal file
54
app/packages/patreon-oauth/patreon_client.js
Normal file
@@ -0,0 +1,54 @@
|
||||
Patreon = {};
|
||||
console.log('patreon-oauth');
|
||||
|
||||
// Request Patreon credentials for the user
|
||||
// @param options {optional}
|
||||
// @param credentialRequestCompleteCallback {Function} Callback function to call on
|
||||
// completion. Takes one argument, credentialToken on success, or Error on
|
||||
// error.
|
||||
Patreon.requestCredential = (options, credentialRequestCompleteCallback) => {
|
||||
// support both (options, callback) and (callback).
|
||||
if (!credentialRequestCompleteCallback && typeof options === 'function') {
|
||||
credentialRequestCompleteCallback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
const config = ServiceConfiguration.configurations.findOne({service: 'patreon'});
|
||||
if (!config) {
|
||||
credentialRequestCompleteCallback && credentialRequestCompleteCallback(
|
||||
new ServiceConfiguration.ConfigError());
|
||||
return;
|
||||
}
|
||||
|
||||
// For some reason, meetup converts underscores to spaces in the state
|
||||
// parameter when redirecting back to the client, so we use
|
||||
// `Random.id()` here (alphanumerics) instead of `Random.secret()`
|
||||
// (base 64 characters).
|
||||
const credentialToken = Random.id();
|
||||
|
||||
const scope = (options && options.requestPermissions) || [
|
||||
'identity',
|
||||
'identity[email]',
|
||||
];
|
||||
const flatScope = scope.map(encodeURIComponent).join(' ');
|
||||
//const flatScope = encodeURIComponent(scope.join(','));
|
||||
|
||||
console.log({flatScope})
|
||||
const loginStyle = OAuth._loginStyle('patreon', config, options);
|
||||
|
||||
const loginUrl =
|
||||
'https://www.patreon.com/oauth2/authorize' +
|
||||
`?client_id=${config.clientId}` +
|
||||
'&response_type=code' +
|
||||
(flatScope ? `&scope=${flatScope}` : '') +
|
||||
`&redirect_uri=${OAuth._redirectUri('patreon', config)}` +
|
||||
`&state=${OAuth._stateParam(loginStyle, credentialToken, options && options.redirectUrl)}`;
|
||||
|
||||
OAuth.launchLogin({
|
||||
loginService: 'patreon',
|
||||
loginStyle,
|
||||
loginUrl,
|
||||
credentialRequestCompleteCallback,
|
||||
credentialToken,
|
||||
});
|
||||
};
|
||||
75
app/packages/patreon-oauth/patreon_server.js
Normal file
75
app/packages/patreon-oauth/patreon_server.js
Normal file
@@ -0,0 +1,75 @@
|
||||
Patreon = {};
|
||||
|
||||
OAuth.registerService('patreon', 2, null, query => {
|
||||
const response = getAccessToken(query);
|
||||
const accessToken = response.access_token;
|
||||
const refreshToken = response.refresh_token;
|
||||
const scope = response.scope;
|
||||
const expiresAt = (+new Date) + (1000 * response.expires_in);
|
||||
const identity = getIdentity(accessToken);
|
||||
let serviceData = {
|
||||
id : identity.data.id,
|
||||
email: identity.data.attributes.email,
|
||||
entitledCents: identity.included[0] &&
|
||||
identity.included[0].attributes.currently_entitled_amount_cents || 0,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
scope,
|
||||
expiresAt,
|
||||
};
|
||||
return { serviceData };
|
||||
});
|
||||
|
||||
const getAccessToken = query => {
|
||||
const config = ServiceConfiguration.configurations.findOne({service: 'patreon'});
|
||||
if (!config)
|
||||
throw new ServiceConfiguration.ConfigError();
|
||||
|
||||
let response;
|
||||
try {
|
||||
response = HTTP.post(
|
||||
'https://www.patreon.com/api/oauth2/token', {headers: {Accept: 'application/json'}, params: {
|
||||
code: query.code,
|
||||
client_id: config.clientId,
|
||||
client_secret: config.secret,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: OAuth._redirectUri('patreon', config),
|
||||
}});
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to complete OAuth handshake with Patreon. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
}
|
||||
|
||||
if (response.data.error) { // if the http response was a json object with an error attribute
|
||||
throw new Error(`Failed to complete OAuth handshake with Patreon. ${response.data.error}`);
|
||||
} else {
|
||||
return response.data;
|
||||
}
|
||||
};
|
||||
|
||||
const getIdentity = accessToken => {
|
||||
try {
|
||||
const response = HTTP.get(
|
||||
'https://www.patreon.com/api/oauth2/v2/identity?' +
|
||||
'fields%5Buser%5D=email&' +
|
||||
'fields%5Bmember%5D=currently_entitled_amount_cents&' +
|
||||
'include=memberships',
|
||||
{
|
||||
headers: {authorization: `Bearer ${accessToken}`},
|
||||
}
|
||||
);
|
||||
let data = JSON.parse(response.content);
|
||||
return data;
|
||||
} catch (err) {
|
||||
throw Object.assign(
|
||||
new Error(`Failed to fetch identity from Patreon. ${err.message}`),
|
||||
{ response: err.response }
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Patreon.retrieveCredential = (credentialToken, credentialSecret) =>
|
||||
OAuth.retrieveCredential(credentialToken, credentialSecret);
|
||||
Reference in New Issue
Block a user