1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-11-28 09:24:24 +01:00

secure the settings API (read) + read the openlab settings from the db

This commit is contained in:
Sylvain 2020-06-08 15:08:07 +02:00
parent db8de18bd4
commit 88f2fb3749
28 changed files with 103 additions and 68 deletions

View File

@ -71,9 +71,8 @@ The deal is fair, you share your projects and as reward you benefits from projec
If you want to try it, you can visit [this Fab-manager](https://fablab.lacasemate.fr/#!/projects) and see projects from different Fab-managers.
To start using this awesome feature, there are a few steps:
- send a mail to **contact@fab-manager.com** asking for your Open Projects client's credentials and giving them the name of your Fab-manager, they will give you an `OPENLAB_APP_ID` and an `OPENLAB_APP_SECRET`
- fill in the value of the keys in your environment file
- start your Fab-manager app
- send a mail to **contact@fab-manager.com** asking for your Open Projects client's credentials and giving them the name and the URL of your Fab-manager, they will give you an `App ID` and a `secret`
- fill in the value of the keys in Admin > Projects > Settings > Projects sharing
- export your projects to open-projects (if you already have projects created on your Fab-manager, unless you can skip that part) executing this command: `bundle exec rake fablab:openlab:bulk_export`
**IMPORTANT: please run your server in production mode.**

View File

@ -87,7 +87,7 @@ class ProjectsController {
$scope.totalSteps = $scope.project.project_steps_attributes.length;
// List of extensions allowed for CAD attachements upload
$scope.allowedExtensions = allowedExtensions;
$scope.allowedExtensions = allowedExtensions.setting.value.split(' ');
/**
* For use with ngUpload (https://github.com/twilson63/ngUpload).
@ -266,8 +266,8 @@ class ProjectsController {
/**
* Controller used on projects listing page
*/
Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'Project', 'machinesPromise', 'themesPromise', 'componentsPromise', 'paginationService', 'OpenlabProject', '$window', 'growl', '_t', '$location', '$timeout',
function ($scope, $state, Project, machinesPromise, themesPromise, componentsPromise, paginationService, OpenlabProject, $window, growl, _t, $location, $timeout) {
Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'Project', 'machinesPromise', 'themesPromise', 'componentsPromise', 'paginationService', 'OpenlabProject', '$window', 'growl', '_t', '$location', '$timeout', 'settingsPromise', 'openLabActive',
function ($scope, $state, Project, machinesPromise, themesPromise, componentsPromise, paginationService, OpenlabProject, $window, growl, _t, $location, $timeout, settingsPromise, openLabActive) {
/* PRIVATE STATIC CONSTANTS */
// Number of projects added to the page when the user clicks on 'load more projects'
@ -277,11 +277,11 @@ Application.Controllers.controller('ProjectsController', ['$scope', '$state', 'P
/* PUBLIC SCOPE */
// Fab-manager's instance ID in the openLab network
$scope.openlabAppId = Fablab.openlabAppId;
$scope.openlabAppId = settingsPromise.openlab_app_id
// Is openLab enabled on the instance?
$scope.openlab = {
projectsActive: Fablab.openlabProjectsActive,
projectsActive: openLabActive.isPresent,
searchOverWholeNetwork: false
};

View File

@ -255,7 +255,9 @@ angular.module('application.router', ['ui.router'])
resolve: {
themesPromise: ['Theme', function (Theme) { return Theme.query().$promise; }],
componentsPromise: ['Component', function (Component) { return Component.query().$promise; }],
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }]
machinesPromise: ['Machine', function (Machine) { return Machine.query().$promise; }],
settingsPromise: ['Setting', function (Setting) { return Setting.query({ names: "['openlab_app_id']" }).$promise; }],
openLabActive: ['Setting', function (Setting) { return Setting.isPresent({ name: 'openlab_app_secret' }).$promise; }],
}
})
.state('app.logged.projects_new', {
@ -267,7 +269,7 @@ angular.module('application.router', ['ui.router'])
}
},
resolve: {
allowedExtensions: ['Project', function (Project) { return Project.allowedExtensions().$promise; }]
allowedExtensions: ['Setting', function (Setting) { return Setting.get({ name: 'allowed_cad_extensions' }).$promise; }]
}
})
.state('app.public.projects_show', {
@ -293,7 +295,7 @@ angular.module('application.router', ['ui.router'])
},
resolve: {
projectPromise: ['$stateParams', 'Project', function ($stateParams, Project) { return Project.get({ id: $stateParams.id }).$promise; }],
allowedExtensions: ['Project', function (Project) { return Project.allowedExtensions().$promise; }]
allowedExtensions: ['Setting', function (Setting) { return Setting.get({ name: 'allowed_cad_extensions' }).$promise; }]
}
})
@ -629,7 +631,7 @@ angular.module('application.router', ['ui.router'])
themesPromise: ['Theme', function (Theme) { return Theme.query().$promise; }],
settingsPromise: ['Setting', function (Setting) {
return Setting.query({ names: "['feature_tour_display', 'disqus_shortname', 'allowed_cad_extensions', \
'allowed_cad_mime_types', 'open_lab_app_id', 'open_lab_app_secret']" }).$promise;
'allowed_cad_mime_types', 'openlab_app_id', 'openlab_app_secret']" }).$promise;
}]
}
})

View File

@ -12,11 +12,6 @@ Application.Services.factory('Project', ['$resource', function ($resource) {
method: 'GET',
url: '/api/projects/search',
isArray: false
},
allowedExtensions: {
method: 'GET',
url: '/api/projects/allowed_extensions',
isArray: true
}
}
);

View File

@ -20,6 +20,11 @@ Application.Services.factory('Setting', ['$resource', function ($resource) {
url: '/api/settings/reset/:name',
params: { name: '@name' },
method: 'PUT'
},
isPresent: {
url: '/api/settings/is_present/:name',
params: { name: '@name' },
method: 'GET'
}
}
);

View File

@ -74,7 +74,7 @@
<text-setting name="openlab_app_id"
settings="allSettings"
label="app.admin.projects.settings.open_lab_app_id"
fa-icon="fa-id-badge">
fa-icon="fa-info">
</text-setting>
</div>
<div class="col-md-4 col-md-offset-2">

View File

@ -54,7 +54,7 @@
</div>
<span class="input-group-addon btn btn-default btn-file"><span class="fileinput-new" translate>{{ 'app.shared.buttons.browse' }}</span>
<span class="fileinput-exists" translate>{{ 'app.shared.buttons.change' }}</span>
<input type="file" name="project[project_caos_attributes][][attachment]" accept="<%= "."+ENV['ALLOWED_EXTENSIONS'].split(' ').join(',.') %>">
<input type="file" name="project[project_caos_attributes][][attachment]" accept="{{'.'+allowedExtensions.join(',.')}}">
</span>
<a class="input-group-addon btn btn-danger fileinput-exists" data-dismiss="fileinput" ng-click="deleteFile(file)"><i class="fa fa-trash-o"></i></a>
</div>

View File

@ -60,10 +60,6 @@ class API::ProjectsController < API::ApiController
render :index
end
def allowed_extensions
render json: ENV['ALLOWED_EXTENSIONS'].split(' '), status: :ok
end
private
def set_project

View File

@ -5,7 +5,7 @@ class API::SettingsController < API::ApiController
before_action :authenticate_user!, only: %i[update bulk_update reset]
def index
@settings = Setting.where(name: names_as_string_to_array)
@settings = policy_scope(Setting.where(name: names_as_string_to_array))
end
def update
@ -35,10 +35,18 @@ class API::SettingsController < API::ApiController
end
def show
authorize SettingContext.new(params[:name])
@setting = Setting.find_or_create_by(name: params[:name])
@show_history = params[:history] == 'true' && current_user.admin?
end
def test_present
authorize SettingContext.new(params[:name])
@setting = Setting.get(params[:name])
end
def reset
authorize Setting

View File

@ -2,7 +2,7 @@
# Mailer configuration
class BaseMailer < ActionMailer::Base
default from: ->(*) { Setting.get('mail_from') }
default from: ->(*) { Setting.get('email_from') }
layout 'notifications_mailer'
helper :application

View File

@ -2,7 +2,7 @@
# Handle most of the emails sent by the platform. Triggered by notifications
class NotificationsMailer < NotifyWith::NotificationsMailer
default from: ->(*) { Setting.get('mail_from') }
default from: ->(*) { Setting.get('email_from') }
layout 'notifications_mailer'
helper :application

View File

@ -5,5 +5,5 @@ class OverwrittenDeviseMailer < Devise::Mailer
helper :application
include Devise::Controllers::UrlHelpers
default template_path: 'devise/mailer'
default from: ->(*) { Setting.get('mail_from') }
default from: ->(*) { Setting.get('email_from') }
end

View File

@ -59,7 +59,7 @@ module Project::OpenlabSync
class_methods do
def openlab_sync_active?
Rails.application.secrets.openlab_app_secret.present?
Setting.get('openlab_app_secret').present?
end
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
# Pundit Additional context to authorize getting a parameter
class SettingContext
attr_reader :name
def initialize(name)
@name = name
end
def policy_class
SettingPolicy
end
end

View File

@ -2,9 +2,50 @@
# Check the access policies for API::SettingsController
class SettingPolicy < ApplicationPolicy
# Defines the scope of the settings index, depending on the role of the current user
class Scope < Scope
def resolve
if user.nil? || (user && !user.admin?)
scope.where.not(name: SettingPolicy.public_blacklist)
else
scope
end
end
end
%w[update bulk_update reset].each do |action|
define_method "#{action}?" do
user.admin?
end
end
def show?
user&.admin? || SettingPolicy.public_whitelist.include?(record.name)
end
def test_present?
user&.admin? || SettingPolicy.public_whitelist.push('openlab_app_secret').include?(record.name)
end
##
# Every settings that anyone can read. The other settings are restricted for admins.
# This list must be manually updated if a new setting should be world-readable
##
def self.public_whitelist
%w[about_title about_body about_contacts privacy_body privacy_dpo twitter_name home_blogpost machine_explications_alert
training_explications_alert training_information_message subscription_explications_alert booking_window_start
booking_window_end booking_slot_duration booking_move_enable booking_move_delay booking_cancel_enable booking_cancel_delay
fablab_name name_genre event_explications_alert space_explications_alert link_name home_content phone_required
tracking_id book_overlapping_slots slot_duration events_in_calendar spaces_module plans_module invoicing_module
recaptcha_site_key feature_tour_display disqus_shortname allowed_cad_extensions openlab_app_id]
end
##
# Every settings that only admins can read.
# This blacklist is automatically generated from the public_whitelist above.
##
def self.public_blacklist
Setting.validators.detect { |v| v.class == ActiveModel::Validations::InclusionValidator && v.attributes.include?(:name) }
.options[:in] - SettingPolicy.public_whitelist
end
end

View File

@ -43,7 +43,7 @@ class HealthService
spaces: Setting.get('spaces_module'),
online_payment: !Rails.application.secrets.fablab_without_online_payments,
invoices: Setting.get('invoicing_module'),
openlab: Rails.application.secrets.openlab_app_secret.present?
openlab: Setting.get('openlab_app_secret').present?
}
end

View File

@ -0,0 +1 @@
json.isPresent @setting.present?

View File

@ -48,11 +48,7 @@
Fablab.weekStartingDay = <%= Date.parse(Rails.application.secrets.week_starting_day).strftime('%w') %>;
Fablab.d3DateFormat = "<%= Rails.application.secrets.d3_date_format %>";
Fablab.uibDateFormat = "<%= Rails.application.secrets.uib_date_format %>";
Fablab.openlabProjectsActive = <%= Rails.application.secrets.openlab_app_secret.present? %>;
Fablab.openlabDefault = ('<%= Rails.application.secrets.openlab_default %>' !== 'false');
<% if Rails.application.secrets.openlab_app_id.present? %>
Fablab.openlabAppId = "<%= Rails.application.secrets.openlab_app_id %>";
<% end %>
Fablab.userConfirmationNeededToSignIn = ('<%= Rails.application.secrets.user_confirmation_needed_to_sign_in %>' === 'true');
// feature tour (used when feature_tour_display = session)

View File

@ -1,6 +1,3 @@
Openlab.configure do |config|
config.app_secret = Rails.application.secrets.openlab_app_secret
if !Rails.env.production?
config.base_uri = Rails.application.secrets.openlab_base_uri
end
config.base_uri = Rails.application.secrets.openlab_base_uri unless Rails.env.production?
end

View File

@ -158,7 +158,7 @@ en:
file_is_TYPE: "MIME type of this file is {TYPE}"
projects_sharing: "Projects sharing"
open_lab_projects: "OpenLab Projects"
open_lab_info_html: "Share your projects with other Fab Labs and display a gallery of shared projects. Please send an email to <a href='mailto:contact@fab-manager.com'>contact@fab-manager.com</a> to get your access credentials for free."
open_lab_info_html: "Enable OpenLab to share your projects with other Fab Labs and display a gallery of shared projects. Please send an email to <a href='mailto:contact@fab-manager.com'>contact@fab-manager.com</a> to get your access credentials for free."
open_lab_app_id: "ID"
open_lab_app_secret: "Secret"
#track and monitor the trainings
@ -1077,8 +1077,8 @@ en:
disqus_shortname: "Disqus shortname"
COUNT_items_removed: "{COUNT, plural, =1{One item} other{{COUNT} items}} removed"
item_added: "One item added"
openlab_app_id: "OpenLab-Projects ID"
openlab_app_secret: "OpenLab-Projects secret"
openlab_app_id: "OpenLab ID"
openlab_app_secret: "OpenLab secret"
general:
general: "General"
title: "Title"

View File

@ -157,9 +157,9 @@ fr:
set_a_file: "Sélectionner un fichier"
file_is_TYPE: "Le type MIME de ce fichier est {TYPE}"
projects_sharing: "Partage de projets"
open_lab_projects: "OpenLab Projects"
open_lab_info_html: "Partagez vos projets avec d'autres Fab Labs et affichez une galerie de projets partagés. Veuillez envoyer un courriel à <a href='mailto:contact@fab-manager.com'>contact@fab-manager.com</a> pour obtenir gratuitement vos identifiants d'accès."
open_lab_app_id: "ID"
open_lab_projects: "Projets OpenLab"
open_lab_info_html: "Activez OpenLab pout partager vos projets avec d'autres Fab Labs et afficher une galerie de projets partagés. Veuillez envoyer un courriel à <a href='mailto:contact@fab-manager.com'>contact@fab-manager.com</a> pour obtenir gratuitement vos identifiants d'accès."
open_lab_app_id: "Identifiant"
open_lab_app_secret: "Secret"
#track and monitor the trainings
trainings:
@ -1077,8 +1077,8 @@ fr:
disqus_shortname: "nom court Disqus"
COUNT_items_removed: "{COUNT, plural, =1{Un élément retiré} other{{COUNT} éléments retirés}}"
item_added: "Un élément ajouté"
openlab_app_id: "l'ID OpenLab-Projects"
openlab_app_secret: "secret OpenLab-Projects"
openlab_app_id: "l'identifiant OpenLab"
openlab_app_secret: "secret OpenLab"
general:
general: "Général"
title: "Titre"

View File

@ -32,7 +32,6 @@ Rails.application.routes.draw do
collection do
get :last_published
get :search
get :allowed_extensions
end
end
resources :openlab_projects, only: :index
@ -44,6 +43,7 @@ Rails.application.routes.draw do
resources :settings, only: %i[show update index], param: :name do
patch '/bulk_update', action: 'bulk_update', on: :collection
put '/reset/:name', action: 'reset', on: :collection
get '/is_present/:name', action: 'test_present', on: :collection
end
resources :users, only: %i[index create destroy]
resources :members, only: %i[index show create update destroy] do

View File

@ -32,8 +32,6 @@ development:
angular_locale: <%= ENV["ANGULAR_LOCALE"] %>
fullcalendar_locale: <%= ENV["FULLCALENDAR_LOCALE"] %>
elasticsearch_language_analyzer: <%= ENV["ELASTICSEARCH_LANGUAGE_ANALYZER"] %>
openlab_app_secret: <%= ENV["OPENLAB_APP_SECRET"] %>
openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %>
openlab_default: <%= ENV["OPENLAB_DEFAULT"] %>
openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %>
navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %>
@ -68,8 +66,6 @@ test:
angular_locale: en-us
fullcalendar_locale: en
elasticsearch_language_analyzer: french
openlab_app_secret:
openlab_app_id:
openlab_default:
openlab_base_uri:
navinum_api_login:
@ -112,8 +108,6 @@ staging:
angular_locale: <%= ENV["ANGULAR_LOCALE"] %>
fullcalendar_locale: <%= ENV["FULLCALENDAR_LOCALE"] %>
elasticsearch_language_analyzer: <%= ENV["ELASTICSEARCH_LANGUAGE_ANALYZER"] %>
openlab_app_secret: <%= ENV["OPENLAB_APP_SECRET"] %>
openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %>
openlab_default: <%= ENV["OPENLAB_DEFAULT"] %>
openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %>
navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %>
@ -159,8 +153,6 @@ production:
angular_locale: <%= ENV["ANGULAR_LOCALE"] %>
fullcalendar_locale: <%= ENV["FULLCALENDAR_LOCALE"] %>
elasticsearch_language_analyzer: <%= ENV["ELASTICSEARCH_LANGUAGE_ANALYZER"] %>
openlab_app_secret: <%= ENV["OPENLAB_APP_SECRET"] %>
openlab_app_id: <%= ENV["OPENLAB_APP_ID"] %>
openlab_default: <%= ENV["OPENLAB_DEFAULT"] %>
openlab_base_uri: <%= ENV["OPENLAB_BASE_URI"] %>
navinum_api_login: <%= ENV["NAVINUM_API_LOGIN"] %>

View File

@ -280,13 +280,6 @@ See [Crowdin documentation](https://support.crowdin.com/in-context-localization/
Accordingly, `RAILS_LOCALE` and `APP_LOCALE` must be configured to `zu`.
<a name="open-projects-settings"></a>
## OpenLab settings
<a name="OPENLAB_APP_ID"></a><a name="OPENLAB_APP_SECRET"></a>
OPENLAB_APP_ID, OPENLAB_APP_SECRET
This configuration is optional and can only work in production mode.
It allows you to display a shared projects gallery and to share your projects with other fablabs.
Send an email to **contact@fab-manager.com** to get your OpenLab client's credentials.
<a name="OPENLAB_DEFAULT"></a>
OPENLAB_DEFAULT

View File

@ -56,8 +56,6 @@ UIB_DATE_FORMAT=dd/MM/yyyy
EXCEL_DATE_FORMAT=dd/mm/yyyy
# OpenLab Projects
OPENLAB_APP_SECRET=
OPENLAB_APP_ID=
OPENLAB_DEFAULT=true
# do not change this URL
OPENLAB_BASE_URI=https://openprojects.fab-manager.com

View File

@ -5,13 +5,13 @@ namespace :fablab do
namespace :openlab do
desc 'bulk and export projects to openlab'
task bulk_export: :environment do
if Rails.application.secrets.openlab_app_secret.present?
if Setting.get('openlab_app_secret').present?
Project.find_each do |project|
project.openlab_create
puts '-> Done'
end
else
warn "Rails.application.secrets.openlab_app_secret not present. Export can't be done."
warn "Openlab_app_secret was not configured. Export can't be done."
end
end
end

View File

@ -44,8 +44,6 @@ D3_DATE_FORMAT=%d/%m/%y
UIB_DATE_FORMAT=dd/MM/yyyy
EXCEL_DATE_FORMAT=dd/mm/yyyy
OPENLAB_APP_SECRET=
OPENLAB_APP_ID=
OPENLAB_DEFAULT='true'
OPENLAB_BASE_URI=https://openprojects.fab-manager.com

View File

@ -239,7 +239,7 @@ configure_env_file()
SMTP_ENABLE_STARTTLS_AUTO SMTP_OPENSSL_VERIFY_MODE SMTP_TLS \
LOG_LEVEL MAX_IMAGE_SIZE MAX_CAO_SIZE MAX_IMPORT_SIZE DISK_SPACE_MB_ALERT \
SUPERADMIN_EMAIL APP_LOCALE RAILS_LOCALE MOMENT_LOCALE SUMMERNOTE_LOCALE ANGULAR_LOCALE FULLCALENDAR_LOCALE ELASTICSEARCH_LANGUAGE_ANALYZER TIME_ZONE \
WEEK_STARTING_DAY D3_DATE_FORMAT UIB_DATE_FORMAT EXCEL_DATE_FORMAT OPENLAB_APP_ID OPENLAB_APP_SECRET OPENLAB_DEFAULT)
WEEK_STARTING_DAY D3_DATE_FORMAT UIB_DATE_FORMAT EXCEL_DATE_FORMAT OPENLAB_DEFAULT)
for variable in "${variables[@]}"; do
local var_doc current
var_doc=$(get_md_anchor "$doc" "$variable")