diff options
author | Azul <azul@riseup.net> | 2016-10-20 14:39:33 +0200 |
---|---|---|
committer | Azul <azul@riseup.net> | 2016-10-20 14:39:33 +0200 |
commit | b97daaed9b513006ace7e8eb5232a2211e965e77 (patch) | |
tree | e27002e8368e92410e5d4af2a945260c2ea6e2d1 /app/controllers/api | |
parent | c6c4d9fd10b8ca8e24889112727e44c9bf68dd60 (diff) | |
parent | 6eb2dae802e5453e2a4361ab28f614cce9294f4c (diff) |
Merge remote-tracking branch 'origin/develop'
We'll only use the master branch for development from now on.
Diffstat (limited to 'app/controllers/api')
-rw-r--r-- | app/controllers/api/certs_controller.rb | 31 | ||||
-rw-r--r-- | app/controllers/api/configs_controller.rb | 41 | ||||
-rw-r--r-- | app/controllers/api/identities_controller.rb | 18 | ||||
-rw-r--r-- | app/controllers/api/messages_controller.rb | 119 | ||||
-rw-r--r-- | app/controllers/api/services_controller.rb | 10 | ||||
-rw-r--r-- | app/controllers/api/sessions_controller.rb | 45 | ||||
-rw-r--r-- | app/controllers/api/smtp_certs_controller.rb | 42 | ||||
-rw-r--r-- | app/controllers/api/users_controller.rb | 94 |
8 files changed, 400 insertions, 0 deletions
diff --git a/app/controllers/api/certs_controller.rb b/app/controllers/api/certs_controller.rb new file mode 100644 index 0000000..46a84d3 --- /dev/null +++ b/app/controllers/api/certs_controller.rb @@ -0,0 +1,31 @@ +class Api::CertsController < ApiController + + before_filter :require_login, :unless => :anonymous_access_allowed? + before_filter :require_enabled + + # GET /cert + # deprecated - we actually create a new cert and that can + # be reflected in the action. GET /cert will eventually go + # away and be replaced by POST /cert + def show + create + end + + # POST /cert + def create + @cert = ClientCertificate.new(:prefix => service_level.cert_prefix) + render text: @cert.to_s, content_type: 'text/plain' + end + + protected + + def require_enabled + if !current_user.is_anonymous? && !current_user.enabled? + access_denied + end + end + + def service_level + current_user.effective_service_level + end +end diff --git a/app/controllers/api/configs_controller.rb b/app/controllers/api/configs_controller.rb new file mode 100644 index 0000000..0f9b8a6 --- /dev/null +++ b/app/controllers/api/configs_controller.rb @@ -0,0 +1,41 @@ +class Api::ConfigsController < ApiController + include ControllerExtension::JsonFile + + before_filter :require_login, :unless => :anonymous_access_allowed? + before_filter :sanitize_id, only: :show + + def index + render json: {services: service_paths} + end + + def show + send_file lookup_file + end + + protected + + SERVICE_IDS = { + soledad: "soledad-service", + eip: "eip-service", + smtp: "smtp-service" + } + + def service_paths + Hash[SERVICE_IDS.map{|k,v| [k,"/#{api_version}/configs/#{v}.json"] } ] + end + + def api_version + ["1", "2"].include?(params[:version]) ? params[:version] : "2" + end + + def sanitize_id + @id = params[:id].downcase + access_denied unless SERVICE_IDS.values.include? @id + end + + def lookup_file + path = APP_CONFIG[:config_file_paths][@id] + not_found if path.blank? + Rails.root.join path + end +end diff --git a/app/controllers/api/identities_controller.rb b/app/controllers/api/identities_controller.rb new file mode 100644 index 0000000..de4910a --- /dev/null +++ b/app/controllers/api/identities_controller.rb @@ -0,0 +1,18 @@ +module Api + class IdentitiesController < ApiController + before_filter :token_authenticate + before_filter :require_monitor + + respond_to :json + + def show + @identity = Identity.find_by_address(params[:id]) + if @identity + respond_with @identity + else + render_not_found + end + end + + end +end diff --git a/app/controllers/api/messages_controller.rb b/app/controllers/api/messages_controller.rb new file mode 100644 index 0000000..a69a40a --- /dev/null +++ b/app/controllers/api/messages_controller.rb @@ -0,0 +1,119 @@ +module Api + class MessagesController < ApiController + + before_filter :require_login + + def index + if Dir.exist?(motd_dir) + if !CommonLanguages::available_code?(params[:locale]) + locale = 'en' + else + locale = params[:locale] + end + render json: motd_files_for_locale(locale) + else + render json: [] + end + end + + # disable per-user messages for now, not supported in the client + #def update + # if message = Message.find(params[:id]) + # message.mark_as_read_by(current_user) + # message.save + # render json: success(:marked_as_read) + # else + # render json: error(:not_found), status: :not_found + # end + #end + + private + + # + # returns list of messages, for example: + # + # [ + # {"id": 1, "locale": "en", "text": "<message text>"}, + # {"id": 2, "locale": "en", "text": "<message text>"} + # ] + # + # Each message is present only once, using the best choice + # for the locale. The order is determined by the id. + # + def motd_files_for_locale(locale) + files = [] + motd_files.keys.each do |id| + if motd_files[id].key?(locale) + msg_locale = locale + elsif motd_files[id].key?('en') + msg_locale = 'en' + else + msg_locale = motd_files[id].keys.first + end + files << { + "id" => id, + "locale" => msg_locale, + "text" => motd_files[id][msg_locale] + } + end + files.sort! {|a,b| a["id"].to_i <=> b["id"].to_i } + return files + end + + # + # returns messages of the day as a hash: + # { "1": {"en": "message"}, "2": {"en": "message"} } + # + def motd_files + if motd_changed? || @motd_files.nil? + @motd_files = load_motd_files + else + @motd_files + end + end + + def motd_changed? + newest = Dir.glob(File.join(motd_dir, '*.{html,md}')).collect{|file| File.mtime(file)}.max + if @timestamp.nil? + @timestamp = newest + return true + elsif @timestamp < newest + @timestamp = newest + return true + else + return false + end + end + + def load_motd_files + files = {} + Dir.glob(File.join(motd_dir, '*.{html,md}')).each do |file| + id, locale, msg = parse_motd_file(file) + next unless id + files[id] ||= {} + files[id][locale] = msg + end + files + end + + def parse_motd_file(file) + id, locale, ext = File.basename(file).split('.') + if id.nil? || locale.nil? || ext.nil? || id.to_i.to_s != id || !['md', 'html'].include?(ext) + Rails.logger.error "ERROR: Could not parse MOTD file #{file}" + return nil + end + contents = File.read(file) + if ext == "md" + msg = RDiscount.new(contents, :autolink).to_html + elsif ext == "html" + msg = File.read(file) + end + return id, locale, msg + end + + def motd_dir + File.join(APP_CONFIG['customization_directory'], 'motd') + end + + end +end diff --git a/app/controllers/api/services_controller.rb b/app/controllers/api/services_controller.rb new file mode 100644 index 0000000..58e129c --- /dev/null +++ b/app/controllers/api/services_controller.rb @@ -0,0 +1,10 @@ +class Api::ServicesController < ApiController + + before_filter :require_login, :unless => :anonymous_access_allowed? + + respond_to :json + + def show + respond_with current_user.effective_service_level + end +end diff --git a/app/controllers/api/sessions_controller.rb b/app/controllers/api/sessions_controller.rb new file mode 100644 index 0000000..178f86e --- /dev/null +++ b/app/controllers/api/sessions_controller.rb @@ -0,0 +1,45 @@ +module Api + class SessionsController < ApiController + + before_filter :require_login, only: :destroy + respond_to :json + + def new + @session = Session.new + if authentication_errors + @errors = authentication_errors + render :status => 422 + end + end + + def create + logout if logged_in? + if params['A'] + authenticate! + else + @user = User.find_by_login(params['login']) + render :json => {salt: @user.salt} + end + end + + def update + authenticate! + @token = Token.create(:user_id => current_user.id) + session[:token] = @token.id + render :json => login_response + end + + def destroy + logout + head :no_content + end + + protected + + def login_response + handshake = session.delete(:handshake) || {} + handshake.to_hash.merge(:id => current_user.id, :token => @token.to_s) + end + + end +end diff --git a/app/controllers/api/smtp_certs_controller.rb b/app/controllers/api/smtp_certs_controller.rb new file mode 100644 index 0000000..d9eab7d --- /dev/null +++ b/app/controllers/api/smtp_certs_controller.rb @@ -0,0 +1,42 @@ +class Api::SmtpCertsController < ApiController + + before_filter :require_login + before_filter :require_email_account + before_filter :fetch_identity + before_filter :require_enabled + + # POST /1/smtp_cert + def create + @cert = ClientCertificate.new common_name: current_user.email_address + @identity.register_cert(@cert) + @identity.save + render text: @cert.to_s, content_type: 'text/plain' + end + + protected + + # + # Filters + # + + def require_email_account + access_denied unless service_level.provides? 'email' + end + + def require_enabled + access_denied unless current_user.enabled? + end + + def fetch_identity + @identity = current_user.identity + end + + # + # Helper methods + # + + def service_level + current_user.effective_service_level + end + +end diff --git a/app/controllers/api/users_controller.rb b/app/controllers/api/users_controller.rb new file mode 100644 index 0000000..709e076 --- /dev/null +++ b/app/controllers/api/users_controller.rb @@ -0,0 +1,94 @@ +module Api + class UsersController < ApiController + include ControllerExtension::FetchUser + + # allow optional access to this controller using API auth tokens: + before_filter :token_authenticate + + before_filter :fetch_user, :only => [:update, :destroy] + before_filter :require_monitor, :only => [:index, :show] + before_filter :require_login, :only => [:index, :update, :destroy] + + respond_to :json + + # used for autocomplete for admins in the web ui + def index + if params[:query] + @users = User.login_starts_with(params[:query]) + respond_with @users.map(&:login).sort + else + render :json => {'error' => 'query required', 'status' => :unprocessable_entity} + end + end + + def show + if params[:login] + @user = User.find_by_login(params[:login]) + elsif params[:id] + @user = User.find(params[:id]) + end + if @user + respond_with user_response + else + not_found + end + end + + def user_response + @user.to_hash.tap do |user_hash| + if @user == current_user + user_hash['is_admin'] = @user.is_admin? + end + end + end + + def create + if current_user.is_monitor? + create_test_account + elsif APP_CONFIG[:allow_registration] + create_account + else + head :forbidden + end + end + + def update + @user.account.update params[:user] + respond_with @user + end + + def destroy + @user.account.destroy(release_handles) + if @user == current_user + logout + end + render :json => {'success' => 'user deleted'} + end + + private + + def release_handles + current_user.is_monitor? || params[:identities] == "destroy" + end + + # tester auth can only create test users. + def create_test_account + if User::is_test?(params[:user][:login]) + @user = Account.create(params[:user], :invite_required => false) + respond_with @user + else + head :forbidden + end + end + + def create_account + if APP_CONFIG[:allow_registration] + @user = Account.create(params[:user]) + respond_with @user # return ID instead? + else + head :forbidden + end + end + + end +end |