Improve: Marketplace auth inside Rocket.Chat instead of inside the iframe. (#14258)

* Oauth inside Rocket.Chat instead of inside the iframe.  This is more secure.

Refactored the cloud page.  Changed menu to cloud connect, add button for cloud console and many others

* change cloud sync endpoint

* add resend button

* add i18n.  If disconnected and click register again do sync

* more error handling and fall back verbose for now.  Handle disconnect / reconnect case better.
pull/14229/head^2
Aaron Ogle 6 years ago committed by Rodrigo Nascimento
parent ae92a17aeb
commit 67d07a2783
  1. 6
      app/apps/client/admin/apps.html
  2. 48
      app/apps/client/admin/apps.js
  3. 10
      app/apps/server/communication/rest.js
  4. 69
      app/cloud/client/admin/cloud.html
  5. 70
      app/cloud/client/admin/cloud.js
  6. 2
      app/cloud/client/index.js
  7. 22
      app/cloud/server/functions/checkUserHasCloudLogin.js
  8. 2
      app/cloud/server/functions/connectWorkspace.js
  9. 5
      app/cloud/server/functions/finishOAuthAuthorization.js
  10. 99
      app/cloud/server/functions/getUserCloudAccessToken.js
  11. 2
      app/cloud/server/functions/getWorkspaceAccessToken.js
  12. 6
      app/cloud/server/functions/getWorkspaceLicense.js
  13. 1
      app/cloud/server/functions/retrieveRegistrationStatus.js
  14. 19
      app/cloud/server/functions/startRegisterWorkspace.js
  15. 12
      app/cloud/server/functions/syncWorkspace.js
  16. 3
      app/cloud/server/functions/unregisterWorkspace.js
  17. 20
      app/cloud/server/functions/userLoggedOut.js
  18. 51
      app/cloud/server/functions/userLogout.js
  19. 3
      app/cloud/server/index.js
  20. 28
      app/cloud/server/methods.js
  21. 10
      app/lib/server/startup/settings.js
  22. 22
      packages/rocketchat-i18n/i18n/en.i18n.json

@ -6,6 +6,12 @@
{{> icon icon="upload" block="rc-icon--default-size"}} {{_ "Upload app"}}
</button>
{{/if}}
{{#unless cloudLoggedIn}}
<button class="rc-button rc-button--small rc-button--primary rc-button--outline" data-button="login">
{{> icon icon="cloud-plus" block="rc-icon--default-size"}} {{_ "Login"}}
</button>
{{/unless}}
{{/header}}
<div class="rc-table-content">
{{>tabs tabs=tabsData}}

@ -1,4 +1,5 @@
import toastr from 'toastr';
import { Meteor } from 'meteor/meteor';
import { ReactiveVar } from 'meteor/reactive-var';
import { FlowRouter } from 'meteor/kadira:flow-router';
import { Template } from 'meteor/templating';
@ -63,6 +64,17 @@ const getInstalledApps = async (instance) => {
}
};
const getCloudLoggedIn = async (instance) => {
Meteor.call('cloud:checkUserLoggedIn', (error, result) => {
if (error) {
console.warn(error);
return;
}
instance.cloudLoggedIn.set(result);
});
};
Template.apps.onCreated(function() {
const instance = this;
this.ready = new ReactiveVar(false);
@ -77,6 +89,7 @@ Template.apps.onCreated(function() {
this.end = new ReactiveVar(false);
this.isLoading = new ReactiveVar(true);
this.searchType = new ReactiveVar('marketplace');
this.cloudLoggedIn = new ReactiveVar(false);
const queryTab = FlowRouter.getQueryParam('tab');
if (queryTab) {
@ -103,6 +116,8 @@ Template.apps.onCreated(function() {
// });
};
getCloudLoggedIn(instance);
instance.onAppRemoved = function _appOnAppRemoved(appId) {
const apps = instance.apps.get();
@ -151,6 +166,9 @@ Template.apps.helpers({
appsDevelopmentMode() {
return settings.get('Apps_Framework_Development_Mode') === true;
},
cloudLoggedIn() {
return Template.instance().cloudLoggedIn.get();
},
parseStatus(status) {
return t(`App_status_${ status }`);
},
@ -270,6 +288,9 @@ Template.apps.events({
'click [data-button="install"]'() {
FlowRouter.go('/admin/app/install');
},
'click [data-button="login"]'() {
FlowRouter.go('/admin/cloud');
},
'click .js-install'(e, template) {
e.stopPropagation();
const elm = e.currentTarget.parentElement;
@ -298,6 +319,26 @@ Template.apps.events({
const rl = this;
if (!template.cloudLoggedIn.get()) {
modal.open({
title: t('Apps_Marketplace_Login_Required_Title'),
text: t('Apps_Marketplace_Login_Required_Description'),
type: 'info',
showCancelButton: true,
confirmButtonColor: '#DD6B55',
confirmButtonText: t('Login'),
cancelButtonText: t('Cancel'),
closeOnConfirm: true,
html: false,
}, function(confirmed) {
if (confirmed) {
FlowRouter.go('/admin/cloud');
}
return;
});
return;
}
// play animation
const elm = e.currentTarget.parentElement;
@ -328,7 +369,12 @@ Template.apps.events({
});
})
.catch((e) => {
toastr.error((e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message);
const errMsg = (e.xhr.responseJSON && e.xhr.responseJSON.error) || e.message;
toastr.error(errMsg);
if (errMsg === 'Unauthorized') {
getCloudLoggedIn(template);
}
});
},
'keyup .js-search'(e, t) {

@ -3,7 +3,7 @@ import { HTTP } from 'meteor/http';
import { API } from '../../../api/server';
import Busboy from 'busboy';
import { getWorkspaceAccessToken } from '../../../cloud/server';
import { getWorkspaceAccessToken, getUserCloudAccessToken } from '../../../cloud/server';
import { settings } from '../../../settings';
import { Info } from '../../../utils';
@ -94,7 +94,13 @@ export class AppsRestApi {
if (this.queryParams.buildBuyUrl && this.queryParams.appId) {
const workspaceId = settings.get('Cloud_Workspace_Id');
return API.v1.success({ url: `${ baseUrl }/apps/${ this.queryParams.appId }/buy?workspaceId=${ workspaceId }` });
const token = getUserCloudAccessToken(this.getLoggedInUser()._id, true, 'marketplace:purchase', false);
if (!token) {
return API.v1.failure({ error: 'Unauthorized' });
}
return API.v1.success({ url: `${ baseUrl }/apps/${ this.queryParams.appId }/buy?workspaceId=${ workspaceId }&token=${ token }` });
}
const apps = manager.get().map((prl) => {

@ -1,10 +1,13 @@
<template name="cloud">
<div class="main-content-flex">
<section class="page-container page-home page-static page-settings">
{{> header sectionName="Cloud_connect"}}
{{#header sectionName="Cloud_connect" hideHelp=true fixedHeight=true fullpage=true}}
<button type="button" class="rc-button rc-button--primary action cloud-console-btn">{{_ "Cloud_console"}}</button>
{{/header}}
<div class="content">
{{#requiresPermission 'manage-cloud'}}
<div class="section">
<div class="section-title">
<div class="section-title-text">
{{_ "Cloud_what_is_it"}}
@ -14,6 +17,21 @@
<div class="section-content">
<p>{{_ "Cloud_what_is_it_description"}}</p>
</div>
<details>
<div class="section-content">
<p>{{_ "Cloud_what_is_it_services_like"}}</p>
<ul style="list-style-type:disc;margin-left:15px;">
<li>{{_ "Register_Server_Registered_Push_Notifications"}}</li>
<li>{{_ "Register_Server_Registered_Livechat"}}</li>
<li>{{_ "Register_Server_Registered_OAuth"}}</li>
<li>{{_ "Register_Server_Registered_Marketplace"}}</li>
</ul>
</div>
<div class="section-content">
{{_ "Cloud_what_is_it_additional"}}
</div>
</details>
</div>
<div class="section">
{{#if info.connectToCloud}}
@ -21,22 +39,19 @@
<div class="section-content border-component-color">
<p>{{_ "Cloud_workspace_connected"}}</p>
<div class="input-line double-col">
<label class="setting-label" title=""></label>
<div class="setting-field">
<a href="https://cloud.rocket.chat" class="rc-button rc-button--primary" target="_blank">{{_ "Cloud_login_to_cloud"}}</a>
</div>
</div>
</div>
<div class="section-content border-component-color">
<p>{{_ "Cloud_workspace_support"}}</p>
<div class="input-line double-col">
{{#if isLoggedIn}}
<label class="setting-label" title=""></label>
<div class="setting-field">
<button type="button" class="rc-button rc-button--danger action sync-btn">{{_ "Sync"}}</button>
<button type="button" class="rc-button rc-button--primary action logout-btn" target="_blank">{{_ "Cloud_logout"}}</button>
</div>
</div>
{{else}}
<label class="setting-label" title=""></label>
<div class="setting-field">
<button type="button" class="rc-button rc-button--primary action login-btn" target="_blank">{{_ "Cloud_login_to_cloud"}}</button>
</div>
{{/if}}
</div>
</div>
<div class="section-content border-component-color">
<p>{{_ "Cloud_workspace_disconnect"}}</p>
@ -59,7 +74,8 @@
<div class="input-line double-col">
<label class="setting-label" title=""></label>
<div class="setting-field">
<button type="button" class="rc-button rc-button--primary action update-email-btn">{{_ "Cloud_update_email"}}</button>
<button type="button" class="rc-button rc-button--primary action update-email-btn" style="float:left">{{_ "Cloud_update_email"}}</button>
<button type="button" class="rc-button rc-button--primary action resend-email-btn" style="float:left;margin-left:5px;">{{_ "Cloud_resend_email"}}</button>
</div>
</div>
@ -77,7 +93,7 @@
</div>
</div>
<p>If you still haven't received a registration email please make sure your email is updated above. If you still have issues you can contact support at: <a href="mailto:support@rocket.chat?subject=[Self Hosted Registration]&body=WorkspaceId: {{ info.workspaceId }}%0D%0ADeployment Id: {{ info.uniqueId }}%0D%0AIssue: <please describe your issue here>">support@rocket.chat</a></p>
<p>{{_ "Cloud_connect_support"}}: <a href="mailto:support@rocket.chat?subject=[Self Hosted Registration]&body=WorkspaceId: {{ info.workspaceId }}%0D%0ADeployment Id: {{ info.uniqueId }}%0D%0AIssue: <please describe your issue here>">support@rocket.chat</a></p>
</div>
{{/if}}
{{else}}
@ -92,6 +108,29 @@
</div>
{{/if}}
</div>
{{#if info.connectToCloud}}
<div class="section">
<div class="section-title">
<div class="section-title-text">
{{_ "Cloud_troubleshooting"}}
</div>
</div>
<div class="section-content border-component-color">
<p>{{_ "Cloud_workspace_support"}}</p>
<div class="input-line double-col">
<label class="setting-label" title=""></label>
<div class="setting-field">
<button type="button" class="rc-button rc-button--danger action sync-btn">{{_ "Sync"}}</button>
</div>
</div>
</div>
<div class="section-content">
{{_ "Cloud_status_page_description"}}: <a href="https://status.rocket.chat" target="_blank">status.rocket.chat</a>
</div>
</div>
{{/if}}
{{/requiresPermission}}
</div>
</section>

@ -14,6 +14,7 @@ Template.cloud.onCreated(function() {
const instance = this;
instance.info = new ReactiveVar();
instance.loading = new ReactiveVar(true);
instance.isLoggedIn = new ReactiveVar(false);
instance.loadRegStatus = function _loadRegStatus() {
Meteor.call('cloud:checkRegisterStatus', (error, info) => {
@ -27,6 +28,39 @@ Template.cloud.onCreated(function() {
});
};
instance.getLoggedIn = function _getLoggedIn() {
Meteor.call('cloud:checkUserLoggedIn', (error, result) => {
if (error) {
console.warn(error);
return;
}
instance.isLoggedIn.set(result);
});
};
instance.oauthAuthorize = function _oauthAuthorize() {
Meteor.call('cloud:getOAuthAuthorizationUrl', (error, url) => {
if (error) {
console.warn(error);
return;
}
window.location.href = url;
});
};
instance.logout = function _logout() {
Meteor.call('cloud:logout', (error) => {
if (error) {
console.warn(error);
return;
}
instance.getLoggedIn();
});
};
instance.connectWorkspace = function _connectWorkspace(token) {
Meteor.call('cloud:connectWorkspace', token, (error, success) => {
if (error) {
@ -101,9 +135,7 @@ Template.cloud.onCreated(function() {
return;
}
toastr.success(t('Connected'));
instance.loadRegStatus();
return instance.syncWorkspace();
});
};
@ -114,19 +146,24 @@ Template.cloud.onCreated(function() {
} else {
instance.loadRegStatus();
}
instance.getLoggedIn();
});
Template.cloud.helpers({
info() {
return Template.instance().info.get();
},
isLoggedIn() {
return Template.instance().isLoggedIn.get();
},
});
Template.cloud.events({
'click .update-email-btn'() {
const val = $('input[name=cloudEmail]').val();
Meteor.call('cloud:updateEmail', val, (error) => {
Meteor.call('cloud:updateEmail', val, false, (error) => {
if (error) {
console.warn(error);
return;
@ -136,6 +173,27 @@ Template.cloud.events({
});
},
'click .resend-email-btn'() {
const val = $('input[name=cloudEmail]').val();
Meteor.call('cloud:updateEmail', val, true, (error) => {
if (error) {
console.warn(error);
return;
}
toastr.success(t('Requested'));
});
},
'click .login-btn'(e, i) {
i.oauthAuthorize();
},
'click .logout-btn'(e, i) {
i.logout();
},
'click .connect-btn'(e, i) {
const token = $('input[name=cloudToken]').val();
@ -153,6 +211,10 @@ Template.cloud.events({
'click .sync-btn'(e, i) {
i.syncWorkspace();
},
'click .cloud-console-btn'() {
window.location.href = 'https://cloud.rocket.chat';
},
});
Template.cloud.onRendered(() => {

@ -23,7 +23,7 @@ FlowRouter.route('/admin/cloud/oauth-callback', {
AdminBox.addOption({
icon: 'cloud-plus',
href: 'admin/cloud',
i18nLabel: 'Cloud',
i18nLabel: 'Cloud Connect',
permissionGranted() {
return hasAtLeastOnePermission(['manage-cloud']);
},

@ -0,0 +1,22 @@
import { Users } from '../../../models';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
export function checkUserHasCloudLogin(userId) {
const { connectToCloud, workspaceRegistered } = retrieveRegistrationStatus();
if (!connectToCloud || !workspaceRegistered) {
return false;
}
if (!userId) {
return false;
}
const user = Users.findOneById(userId);
if (user && user.services && user.services.cloud && user.services.cloud.accessToken) {
return true;
}
return false;
}

@ -32,6 +32,8 @@ export function connectWorkspace(token) {
} catch (e) {
if (e.response && e.response.data && e.response.data.error) {
console.error(`Failed to register with Rocket.Chat Cloud. Error: ${ e.response.data.error }`);
} else {
console.error(e);
}
return false;

@ -1,7 +1,7 @@
import { Meteor } from 'meteor/meteor';
import { HTTP } from 'meteor/http';
import { settings } from '../../../settings';
import { Settings, Users } from '../../../models';
import { Users } from '../../../models';
import { getRedirectUri } from './getRedirectUri';
import { userScopes } from '../oauthScopes';
@ -33,6 +33,8 @@ export function finishOAuthAuthorization(code, state) {
} catch (e) {
if (e.response && e.response.data && e.response.data.error) {
console.error(`Failed to get AccessToken from Rocket.Chat Cloud. Error: ${ e.response.data.error }`);
} else {
console.error(e);
}
return false;
@ -41,7 +43,6 @@ export function finishOAuthAuthorization(code, state) {
const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + result.data.expires_in);
Settings.updateValueById('Cloud_Workspace_Account_Associated', true);
Users.update({ _id: Meteor.userId() }, {
$set: {
'services.cloud': {

@ -0,0 +1,99 @@
import { HTTP } from 'meteor/http';
import { settings } from '../../../settings';
import { Users } from '../../../models';
import { getRedirectUri } from './getRedirectUri';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { unregisterWorkspace } from './unregisterWorkspace';
import { userLoggedOut } from './userLoggedOut';
import { userScopes } from '../oauthScopes';
export function getUserCloudAccessToken(userId, forceNew = false, scope = '', save = true) {
const { connectToCloud, workspaceRegistered } = retrieveRegistrationStatus();
if (!connectToCloud || !workspaceRegistered) {
return '';
}
if (!userId) {
return '';
}
const user = Users.findOneById(userId);
if (!user || !user.services || !user.services.cloud || !user.services.cloud.accessToken || !user.services.cloud.refreshToken) {
return '';
}
const { accessToken, refreshToken } = user.services.cloud;
const client_id = settings.get('Cloud_Workspace_Client_Id');
if (!client_id) {
return '';
}
const expires = user.services.cloud.expiresAt;
const now = new Date();
if (now < expires.value && !forceNew) {
return accessToken;
}
const cloudUrl = settings.get('Cloud_Url');
const client_secret = settings.get('Cloud_Workspace_Client_Secret');
const redirectUri = getRedirectUri();
if (scope === '') {
scope = userScopes.join(' ');
}
let authTokenResult;
try {
authTokenResult = HTTP.post(`${ cloudUrl }/api/oauth/token`, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
params: {
client_id,
client_secret,
refresh_token: refreshToken,
scope,
grant_type: 'refresh_token',
redirect_uri: redirectUri,
},
});
} catch (e) {
if (e.response && e.response.data && e.response.data.error) {
console.error(`Failed to get User AccessToken from Rocket.Chat Cloud. Error: ${ e.response.data.error }`);
if (e.response.data.error === 'oauth_invalid_client_credentials') {
console.error('Server has been unregistered from cloud');
unregisterWorkspace();
}
if (e.response.data.error === 'unauthorized') {
userLoggedOut(userId);
}
} else {
console.error(e);
}
return '';
}
if (save) {
const expiresAt = new Date();
expiresAt.setSeconds(expiresAt.getSeconds() + authTokenResult.data.expires_in);
Users.update(user._id, {
$set: {
services: {
cloud: {
accessToken: authTokenResult.data.access_token,
expiresAt,
},
},
},
});
}
return authTokenResult.data.access_token;
}

@ -54,6 +54,8 @@ export function getWorkspaceAccessToken(forceNew = false, scope = '', save = tru
console.error('Server has been unregistered from cloud');
unregisterWorkspace();
}
} else {
console.error(e);
}
return '';

@ -20,6 +20,12 @@ export function getWorkspaceLicense() {
},
});
} catch (e) {
if (e.response && e.response.data && e.response.data.error) {
console.error(`Failed to update license from Rocket.Chat Cloud. Error: ${ e.response.data.error }`);
} else {
console.error(e);
}
return { updated: false, license: '' };
}

@ -5,7 +5,6 @@ export function retrieveRegistrationStatus() {
const info = {
connectToCloud: settings.get('Register_Server'),
workspaceRegistered: (settings.get('Cloud_Workspace_Client_Id')) ? true : false,
userAssociated: (settings.get('Cloud_Workspace_Account_Associated')) ? true : false,
workspaceId: settings.get('Cloud_Workspace_Id'),
uniqueId: settings.get('uniqueID'),
token: '',

@ -5,8 +5,9 @@ import { Settings } from '../../../models';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { statistics } from '../../../statistics';
import { syncWorkspace } from './syncWorkspace';
export function startRegisterWorkspace() {
export function startRegisterWorkspace(resend = false) {
const { workspaceRegistered, connectToCloud } = retrieveRegistrationStatus();
if ((workspaceRegistered && connectToCloud) || process.env.TEST_MODE) {
return true;
@ -14,8 +15,11 @@ export function startRegisterWorkspace() {
settings.updateById('Register_Server', true);
// If we still have client id lets see if they are still good before trying to register
if (workspaceRegistered) {
return true;
if (syncWorkspace(true)) {
return true;
}
}
const stats = statistics.get();
@ -42,13 +46,16 @@ export function startRegisterWorkspace() {
let result;
try {
result = HTTP.post(`${ cloudUrl }/api/v2/register/workspace`, {
result = HTTP.post(`${ cloudUrl }/api/v2/register/workspace?resend=${ resend }`, {
data: regInfo,
});
} catch (e) {
if (e.response && e.response.data && e.response.data.errorCode) {
console.error(`Failed to register with Rocket.Chat Cloud. ErrorCode: ${ e.response.data.errorCode }`);
if (e.response && e.response.data && e.response.data.error) {
console.error(`Failed to register with Rocket.Chat Cloud. ErrorCode: ${ e.response.data.error }`);
} else {
console.error(e);
}
return false;
}
@ -60,7 +67,5 @@ export function startRegisterWorkspace() {
Settings.updateValueById('Cloud_Workspace_Id', data.id);
console.log(data);
return true;
}

@ -7,9 +7,9 @@ import { getWorkspaceAccessToken } from './getWorkspaceAccessToken';
import { statistics } from '../../../statistics';
import { getWorkspaceLicense } from './getWorkspaceLicense';
export function syncWorkspace() {
export function syncWorkspace(reconnectCheck = false) {
const { workspaceRegistered, connectToCloud } = retrieveRegistrationStatus();
if (!workspaceRegistered || !connectToCloud) {
if (!workspaceRegistered || (!connectToCloud && !reconnectCheck)) {
return false;
}
@ -41,18 +41,22 @@ export function syncWorkspace() {
return false;
}
HTTP.post(`${ workspaceUrl }/registration`, {
HTTP.post(`${ workspaceUrl }/client`, {
data: info,
headers,
});
getWorkspaceLicense();
} catch (e) {
if (e.response && e.response.data && e.response.data.error) {
console.error(`Failed to sync with Rocket.Chat Cloud. Error: ${ e.response.data.error }`);
} else {
console.error(e);
}
return false;
}
return getWorkspaceLicense();
return true;
}

@ -15,8 +15,5 @@ export function unregisterWorkspace() {
Settings.updateValueById('Cloud_Workspace_Client_Secret_Expires_At', null);
Settings.updateValueById('Cloud_Workspace_Registration_Client_Uri', null);
// So doesn't try to register again automatically
Settings.updateValueById('Register_Server', false);
return true;
}

@ -0,0 +1,20 @@
import { Users } from '../../../models';
export function userLoggedOut(userId) {
if (!userId) {
return false;
}
const user = Users.findOneById(userId);
if (user && user.services && user.services.cloud) {
Users.update(user._id, {
$unset: {
'services.cloud': 1,
},
});
}
return true;
}

@ -0,0 +1,51 @@
import { HTTP } from 'meteor/http';
import { Users } from '../../../models';
import { userLoggedOut } from './userLoggedOut';
import { retrieveRegistrationStatus } from './retrieveRegistrationStatus';
import { settings } from '../../../settings';
export function userLogout(userId) {
const { connectToCloud, workspaceRegistered } = retrieveRegistrationStatus();
if (!connectToCloud || !workspaceRegistered) {
return '';
}
if (!userId) {
return '';
}
const user = Users.findOneById(userId);
if (user && user.services && user.services.cloud && user.services.cloud.refreshToken) {
try {
const client_id = settings.get('Cloud_Workspace_Client_Id');
if (!client_id) {
return '';
}
const cloudUrl = settings.get('Cloud_Url');
const client_secret = settings.get('Cloud_Workspace_Client_Secret');
const { refreshToken } = user.services.cloud;
HTTP.post(`${ cloudUrl }/api/oauth/revoke`, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
params: {
client_id,
client_secret,
token: refreshToken,
token_type_hint: 'refresh_token',
},
});
} catch (e) {
if (e.response && e.response.data && e.response.data.error) {
console.error(`Failed to get Revoke refresh token to logout of Rocket.Chat Cloud. Error: ${ e.response.data.error }`);
} else {
console.error(e);
}
}
}
return userLoggedOut(userId);
}

@ -1,6 +1,7 @@
import './methods';
import { getWorkspaceAccessToken } from './functions/getWorkspaceAccessToken';
import { getWorkspaceLicense } from './functions/getWorkspaceLicense';
import { getUserCloudAccessToken } from './functions/getUserCloudAccessToken';
import { Permissions } from '../../models';
@ -11,4 +12,4 @@ if (Permissions) {
// Ensure the client/workspace access token is valid
getWorkspaceAccessToken();
export { getWorkspaceAccessToken, getWorkspaceLicense };
export { getWorkspaceAccessToken, getWorkspaceLicense, getUserCloudAccessToken };

@ -10,6 +10,8 @@ import { finishOAuthAuthorization } from './functions/finishOAuthAuthorization';
import { startRegisterWorkspace } from './functions/startRegisterWorkspace';
import { disconnectWorkspace } from './functions/disconnectWorkspace';
import { syncWorkspace } from './functions/syncWorkspace';
import { checkUserHasCloudLogin } from './functions/checkUserHasCloudLogin';
import { userLogout } from './functions/userLogout';
Meteor.methods({
'cloud:checkRegisterStatus'() {
@ -34,7 +36,7 @@ Meteor.methods({
return startRegisterWorkspace();
},
'cloud:updateEmail'(email) {
'cloud:updateEmail'(email, resend = false) {
check(email, String);
if (!Meteor.userId()) {
@ -47,7 +49,7 @@ Meteor.methods({
Settings.updateValueById('Organization_Email', email);
return startRegisterWorkspace();
return startRegisterWorkspace(resend);
},
'cloud:syncWorkspace'() {
if (!Meteor.userId()) {
@ -110,4 +112,26 @@ Meteor.methods({
return finishOAuthAuthorization(code, state);
},
'cloud:checkUserLoggedIn'() {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'cloud:connectServer' });
}
if (!hasPermission(Meteor.userId(), 'manage-cloud')) {
throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'cloud:connectServer' });
}
return checkUserHasCloudLogin(Meteor.userId());
},
'cloud:logout'() {
if (!Meteor.userId()) {
throw new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'cloud:connectServer' });
}
if (!hasPermission(Meteor.userId(), 'manage-cloud')) {
throw new Meteor.Error('error-not-authorized', 'Not authorized', { method: 'cloud:connectServer' });
}
return userLogout(Meteor.userId());
},
});

@ -2665,16 +2665,6 @@ settings.addGroup('Setup_Wizard', function() {
value: true,
},
});
this.add('Cloud_Workspace_Account_Associated', false, {
type: 'boolean',
hidden: true,
readonly: true,
enableQuery: {
_id: 'Register_Server',
value: true,
},
});
});
});

@ -350,6 +350,8 @@
"Apps_Framework_Development_Mode": "Enable development mode",
"Apps_Framework_Development_Mode_Description": "Development mode allows the installation of Apps that are not from the Rocket.Chat's Marketplace.",
"Apps_Framework_enabled": "Enable the App Framework",
"Apps_Marketplace_Login_Required_Title": "Marketplace Login Required",
"Apps_Marketplace_Login_Required_Description": "Purchasing apps from the Rocket.Chat Marketplace requires registering your workspace and logging in.",
"Apps_Settings": "App's Settings",
"Apps_WhatIsIt": "Apps: What Are They?",
"Apps_WhatIsIt_paragraph1": "A new icon in the administration area! What does this mean and what are Apps?",
@ -604,23 +606,29 @@
"Closed_by_visitor": "Closed by visitor",
"Closing_chat": "Closing chat",
"Cloud": "Cloud",
"Cloud_workspace_connected_plus_account": "Your workspace is now connected to the Rocket.Chat Cloud and an account is associated.",
"Cloud_connect": "Rocket.Chat Cloud Connect",
"Cloud_workspace_connected_without_account": "Your workspace is now connected to the Rocket.Chat Cloud. If you would like, you can login to the Rocket.Chat Cloud and associate your workspace with your Cloud account.",
"Cloud_connect_support": "If you still haven't received a registration email please make sure your email is updated above. If you still have issues you can contact support at",
"Cloud_console": "Cloud Console",
"Cloud_what_is_it": "What is this?",
"Cloud_what_is_it_description": "Rocket.Chat Cloud Connect allows you to connect your self-hosted Rocket.Chat Workspace to our Cloud. Doing so enables you to manage your licenses, Billing and Support in Rocket.Chat Cloud.",
"Cloud_workspace_connected": "Your workspace has been successfully connected to Rocket.Chat Cloud. You can access the cloud to manage account information",
"Cloud_workspace_support": "If you have any trouble with a cloud service, please try to sync first. Should the issue persist, please open a support ticket in the Cloud Console.",
"Cloud_workspace_disconnect": "If you no longer wish to utilize cloud services you can disconnect your workspace from the Rocket.Chat Cloud.",
"Cloud_what_is_it_description": "Rocket.Chat Cloud Connect allows you to connect your self-hosted Rocket.Chat Workspace to services we provide in our Cloud.",
"Cloud_what_is_it_services_like": "Services like:",
"Cloud_what_is_it_additional": "In addition you will be able to manage licenses, billing and support from the Rocket.Chat Cloud Console.",
"Cloud_workspace_connected": "Your workspace is connected to Rocket.Chat Cloud. Logging into your Rocket.Chat Cloud account here will allow you to interact with some services like marketplace.",
"Cloud_workspace_support": "If you have trouble with a cloud service, please try to sync first. Should the issue persist, please open a support ticket in the Cloud Console.",
"Cloud_workspace_disconnect": "If you no longer wish to utilize cloud services you can disconnect your workspace from Rocket.Chat Cloud.",
"Cloud_login_to_cloud": "Login to Rocket.Chat Cloud",
"Cloud_logout": "Logout of Rocket.Chat Cloud",
"Cloud_address_to_send_registration_to": "The address to send your Cloud registration email to.",
"Cloud_update_email": "Update Email",
"Cloud_resend_email": "Resend Email",
"Cloud_manually_input_token": "Manually enter the token received from the Cloud Registration Email.",
"Cloud_registration_required": "Registration Required",
"Cloud_registration_required_description": "Looks like during setup you didn't chose to register your workspace.",
"Cloud_registration_requried_link_text": "Click here to register your workspace.",
"Cloud_error_in_authenticating": "Error received while authenticating",
"Cloud_error_code": "Code: ",
"Cloud_status_page_description": "If a particular Cloud Service is having issues you can check for known issues on our status page at",
"Cloud_troubleshooting": "Troubleshooting",
"Collaborative": "Collaborative",
"Collapse_Embedded_Media_By_Default": "Collapse Embedded Media by Default",
"color": "Color",
@ -3210,4 +3218,4 @@
"Your_question": "Your question",
"Your_server_link": "Your server link",
"Your_workspace_is_ready": "Your workspace is ready to use 🎉"
}
}

Loading…
Cancel
Save