diff --git a/Gemfile b/Gemfile index c5f4f2ab6..c01570e41 100644 --- a/Gemfile +++ b/Gemfile @@ -118,6 +118,10 @@ gem 'deep_cloneable', '~> 3.0.0' # oauth2 gem 'omniauth', '~> 1.9.0' gem 'omniauth-oauth2', '~> 1.6.0' +gem "omniauth-github" +gem "omniauth-rails_csrf_protection" +gem 'omniauth-gitee', '~> 1.0.0' +gem "omniauth-wechat-oauth2" # global var gem 'request_store' diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 4409f04a9..63427aa45 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -32,7 +32,7 @@ class AttachmentsController < ApplicationController def get_file normal_status(-1, "参数缺失") if params[:download_url].blank? url = base_url.starts_with?("https:") ? URI.encode(params[:download_url].to_s.gsub("http:", "https:")) : URI.encode(params[:download_url].to_s) - if url.starts_with?(base_url) + if url.starts_with?(base_url) && !url.starts_with?("#{base_url}/repo") domain = GiteaService.gitea_config[:domain] api_url = GiteaService.gitea_config[:base_url] url = ("/repos"+url.split(base_url + "/api")[1]).gsub('?filepath=', '/').gsub('&', '?') diff --git a/app/controllers/concerns/login_helper.rb b/app/controllers/concerns/login_helper.rb index 86ab175ef..c0e8d01c0 100644 --- a/app/controllers/concerns/login_helper.rb +++ b/app/controllers/concerns/login_helper.rb @@ -11,7 +11,7 @@ module LoginHelper def set_autologin_cookie(user) token = Token.get_or_create_permanent_login_token(user, "autologin") - sync_user_token_to_trustie(user.login, token.value) + # sync_user_token_to_trustie(user.login, token.value) Rails.logger.info "###### def set_autologin_cookie and get_or_create_permanent_login_token result: #{token&.value}" cookie_options = { diff --git a/app/controllers/concerns/register_helper.rb b/app/controllers/concerns/register_helper.rb index e1b7dee24..06c005084 100644 --- a/app/controllers/concerns/register_helper.rb +++ b/app/controllers/concerns/register_helper.rb @@ -1,18 +1,21 @@ module RegisterHelper extend ActiveSupport::Concern - def autologin_register(username, email, password, platform= 'forge', need_edit_info = false) + def autologin_register(username, email, password, platform = 'forge', phone = nil, nickname =nil, need_edit_info = false) result = {message: nil, user: nil} + email = email.blank? ? "#{username}@example.org" : email user = User.new(admin: false, login: username, mail: email, type: "User") user.password = password user.platform = platform + user.phone = phone if phone.present? + user.nickname = nickname if nickname.present? if need_edit_info user.need_edit_info - else + else user.activate end - + return unless user.valid? interactor = Gitea::RegisterInteractor.call({username: username, email: email, password: password}) @@ -67,7 +70,7 @@ module RegisterHelper user.password = params[:password] user.mail = params[:email] - if user.save! + if user.save! sync_params = { password: params[:password].to_s, email: params[:email], @@ -75,9 +78,9 @@ module RegisterHelper new_name: params[:username], source_id: 0 } - + interactor = Gitea::User::UpdateInteractor.call(before_login, sync_params) - if interactor.success? + if interactor.success? result[:user] = user else result[:message] = '用户同步Gitea失败!' diff --git a/app/controllers/oauth/base_controller.rb b/app/controllers/oauth/base_controller.rb index 6956c9ce9..25cfa97db 100644 --- a/app/controllers/oauth/base_controller.rb +++ b/app/controllers/oauth/base_controller.rb @@ -3,6 +3,7 @@ class Oauth::BaseController < ActionController::Base include LoginHelper include ControllerRescueHandler include LoggerHelper + include RegisterHelper # include LaboratoryHelper skip_before_action :verify_authenticity_token @@ -13,13 +14,13 @@ class Oauth::BaseController < ActionController::Base private def tip_exception(status = -1, message) - raise Educoder::TipException.new(status, message) + raise Gitlink::TipException.new(status, message) end - + def tip_show_exception(status = -2, message) - raise Educoder::TipException.new(status, message) + raise Gitlink::TipException.new(status, message) end - + def tip_show(exception) uid_logger("Tip show status is #{exception.status}, message is #{exception.message}") render json: exception.tip_json @@ -35,7 +36,7 @@ class Oauth::BaseController < ActionController::Base end def auth_hash - Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") + # Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") request.env['omniauth.auth'] end diff --git a/app/controllers/oauth/callbacks_controller.rb b/app/controllers/oauth/callbacks_controller.rb new file mode 100644 index 000000000..b97fdc023 --- /dev/null +++ b/app/controllers/oauth/callbacks_controller.rb @@ -0,0 +1,68 @@ +class Oauth::CallbacksController < Oauth::BaseController + def create + process_callback + rescue Exception => e + Rails.logger.info "授权失败:#{e}" + tip_exception("授权失败") + end + + private + + def config_providers + config = Rails.application.config_for(:configuration) + config.dig("oauth").keys + end + + # QQ: {"ret":0,"msg":"","is_lost":0,"nickname":"颜值不算太高","gender":"男","gender_type":1,"province":"","city":"","year":"2013","constellation":"","figureurl":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/30","figureurl_1":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/50","figureurl_2":"http://qzapp.qlogo.cn/qzapp/101508858/0F860F4B329768F47B22341C5FD9089C/100","figureurl_qq_1":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=40\u0026t=1568887757","figureurl_qq_2":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=100\u0026t=1568887757","figureurl_qq":"http://thirdqq.qlogo.cn/g?b=oidb\u0026k=My3segFVHFqVmauibJQUltw\u0026s=140\u0026t=1568887757","figureurl_type":"1","is_yellow_vip":"0","vip":"0","yellow_vip_level":"0","level":"0","is_yellow_year_vip":"0"} + def process_callback + Rails.logger.info("[OAuth2] omniauth.auth -> #{request.env['omniauth.auth'].inspect}") + if auth_hash.blank? + redirect_to("/login") && return + end + + new_user = false + platform = auth_hash[:provider] + uid = auth_hash[:uid] + mail = auth_hash.info.email || nil + nickname = ["gitee", "github"].include?(platform) ? auth_hash.info.name : auth_hash.info.nickname + + open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.find_by(uid: uid) + if open_user.present? && open_user.user.present? + successful_authentication(open_user.user) + else + if current_user.blank? || !current_user.logged? + has_user = User.find_by(mail: mail) + if has_user.present? + "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: has_user.id, uid: uid, extra: auth_hash.extra) + successful_authentication(has_user) + else + new_user = true + login = build_login_name(platform, auth_hash.info.nickname) + mail = "#{login}@example.org" if mail.blank? + code = %W(0 1 2 3 4 5 6 7 8 9) + rand_password = code.sample(10).join + reg_result = autologin_register(login, mail, rand_password, platform, nil, nickname) + Rails.logger.info("[OAuth2] omniauth.auth [reg_result] #{reg_result} ") + if reg_result[:message].blank? + open_user = "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user_id: reg_result[:user][:id], uid: uid, extra: auth_hash.extra) + successful_authentication(open_user.user) + else + tip_exception(reg_result.present? ? reg_result[:message] : "授权失败") + end + end + else + "OpenUsers::#{platform.to_s.capitalize}".constantize.create!(user: current_user, uid: login, extra: auth_hash.extra) + end + end + redirect_to root_path(new_user: new_user) + end + + # gitee,github nickname=login,如果系统未占用保留原用户名 + def build_login_name(provider, nickname) + if ["gitee", "github"].include?(provider) && User.find_by(login: nickname).blank? + nickname + else + User.generate_user_login('p') + end + end +end \ No newline at end of file diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index f3eedd0a1..e365c3e29 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -7,6 +7,7 @@ class SettingsController < ApplicationController get_sub_competitions get_personal_menu get_third_party + get_third_party_new get_top_system_notification end @@ -67,6 +68,23 @@ class SettingsController < ApplicationController url: EducoderOauth.oauth_url } end + + def get_third_party_new + @third_party_new = [] + @third_party_new << { + name: 'educoder', + url: EducoderOauth.oauth_url, + method: 'get' + } + config = Rails.application.config_for(:configuration) + (config.dig("oauth").keys - ["educoder"]).each do |provider| + @third_party_new << { + name: provider, + url: "/auth/#{provider}", + method: 'post' + } + end + end def get_top_system_notification @top_system_notification = SystemNotification.is_top.first diff --git a/app/controllers/statistic_controller.rb b/app/controllers/statistic_controller.rb index 6eaa5bc99..40540e5e5 100644 --- a/app/controllers/statistic_controller.rb +++ b/app/controllers/statistic_controller.rb @@ -2,24 +2,24 @@ class StatisticController < ApplicationController # 平台概况 def platform_profile - @platform_user_query = Statistic::PlatformUserQuery.new(params).call - @platform_project_query = Statistic::PlatformProjectQuery.new(params).call - @platform_course_query = Statistic::PlatformCourseQuery.new(params).call + @platform_user_query = Statistic::PlatformUserQuery.new(params).call rescue [0, 0, 0] + @platform_project_query = Statistic::PlatformProjectQuery.new(params).call rescue [0, 0, 0] + @platform_course_query = Statistic::PlatformCourseQuery.new(params).call rescue [0, 0, 0] end # 平台代码提交数据 def platform_code - @platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call - @platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call + @platform_pull_request_query = Statistic::PlatformPullRequestQuery.new(params).call rescue [0, 0] + @platform_commit_query = Statistic::PlatformCommitQuery.new(params,current_user).call rescue [0, 0] end # 项目案例活跃度排行榜 def active_project_rank - @active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call + @active_project_rank_query = Statistic::ActiveProjectRankQuery.new(params, current_user).call rescue [] end # 开发者活跃度排行榜 def active_developer_rank - @active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call + @active_developer_rank_query = Statistic::ActiveDeveloperRankQuery.new(params, current_user).call rescue [] end end \ No newline at end of file diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index f7029c1cd..11d15b751 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -10,7 +10,7 @@ module RepositoriesHelper end def download_type(str) - default_type = %w(xlsx xls ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv apk) + default_type = %w(ppt pptx pdf zip 7z rar exe pdb obj idb RData rdata doc docx mpp vsdx dot otf eot ttf woff woff2 mp4 mov wmv flv mpeg avi avchd webm mkv apk) default_type.include?(str&.downcase) || str.blank? end diff --git a/app/interactors/gitea/create_file_interactor.rb b/app/interactors/gitea/create_file_interactor.rb index 389813520..cf753767c 100644 --- a/app/interactors/gitea/create_file_interactor.rb +++ b/app/interactors/gitea/create_file_interactor.rb @@ -62,7 +62,7 @@ module Gitea file_params = {} file_params = file_params.merge(branch: @params[:branch]) unless @params[:branch].blank? file_params = file_params.merge(new_branch: @params[:new_branch]) unless @params[:new_branch].blank? - file_params = file_params.merge(content: Base64.encode64(@params[:content] || "")) + file_params = file_params.merge(content: @params[:content] || "") file_params = file_params.merge(message: @params[:message]) unless @params[:message].blank? file_params = file_params.merge(committer: @params[:committer]) file_params diff --git a/app/libs/educoder_oauth/service.rb b/app/libs/educoder_oauth/service.rb index 9d93d314d..1dcb2cfdd 100644 --- a/app/libs/educoder_oauth/service.rb +++ b/app/libs/educoder_oauth/service.rb @@ -15,7 +15,7 @@ module EducoderOauth::Service result rescue Exception => e - raise Educoder::TipException.new(e.message) + raise Gitlink::TipException.new(e.message) end end @@ -27,7 +27,7 @@ module EducoderOauth::Service result = client.auth_code.get_token(code, redirect_uri: EducoderOauth.redirect_uri).to_hash return result rescue Exception => e - raise Educoder::TipException.new(e.message) + raise Gitlink::TipException.new(e.message) end end diff --git a/app/models/open_users/gitee.rb b/app/models/open_users/gitee.rb new file mode 100644 index 000000000..a743eb72c --- /dev/null +++ b/app/models/open_users/gitee.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + +class OpenUsers::Gitee < OpenUser + def nickname + extra&.[]('nickname') + end + + def en_type + 'gitee' + end +end diff --git a/app/models/open_users/github.rb b/app/models/open_users/github.rb new file mode 100644 index 000000000..03c79ba58 --- /dev/null +++ b/app/models/open_users/github.rb @@ -0,0 +1,27 @@ +# == Schema Information +# +# Table name: open_users +# +# id :integer not null, primary key +# user_id :integer +# type :string(255) +# uid :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# extra :text(65535) +# +# Indexes +# +# index_open_users_on_type_and_uid (type,uid) UNIQUE +# index_open_users_on_user_id (user_id) +# + +class OpenUsers::Github < OpenUser + def nickname + extra&.[]('name') + end + + def en_type + 'github' + end +end diff --git a/app/models/user.rb b/app/models/user.rb index 41e932a03..b37ebc039 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -114,7 +114,7 @@ class User < Owner # trustie: 来自Trustie平台 # forge: 平台本身注册的用户 # military: 军科的用户 - enumerize :platform, in: [:forge, :educoder, :trustie, :military], default: :forge, scope: :shallow + enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat], default: :forge, scope: :shallow belongs_to :laboratory, optional: true has_one :user_extension, dependent: :destroy @@ -705,12 +705,13 @@ class User < Owner end def show_real_name - name = lastname + firstname - if name.blank? - nickname.blank? ? login : nickname - else - name - end + # name = lastname + firstname + # if name.blank? + # nickname.blank? ? login : nickname + # else + # name + # end + nickname.blank? ? login : nickname end def update_hashed_password @@ -791,6 +792,15 @@ class User < Owner login end + # 生成数字账号 + CODES = %W(0 1 2 3 4 5 6 7 8 9) + def self.generate_user_login type + code = CODES.sample(8).join + code = type + code.to_s + return User.generate_user_login(type) if User.where(login: code).present? + code + end + def bind_open_user?(type) case type when 'wechat' then wechat_open_user.present? diff --git a/app/services/gitea/repository/entries/create_service.rb b/app/services/gitea/repository/entries/create_service.rb index 1bdc7246d..14b373335 100644 --- a/app/services/gitea/repository/entries/create_service.rb +++ b/app/services/gitea/repository/entries/create_service.rb @@ -56,7 +56,7 @@ class Gitea::Repository::Entries::CreateService < Gitea::ClientService when 403 then error("你没有权限操作!") when 404 then error("你操作的链接不存在!") when 422 - if @body[:new_branch].include?('/') || @body[:new_branch].include?('\'') || @body[:new_branch].include?('^') || @body[:new_branch].include?('*') + if @body[:new_branch].present? && (@body[:new_branch].include?('/') || @body[:new_branch].include?('\'') || @body[:new_branch].include?('^') || @body[:new_branch].include?('*')) error("不合法的分支名称!") else error("#{filepath}文件已存在,不能重复创建!") diff --git a/app/views/settings/show.json.jbuilder b/app/views/settings/show.json.jbuilder index abe8207eb..be79dc594 100644 --- a/app/views/settings/show.json.jbuilder +++ b/app/views/settings/show.json.jbuilder @@ -61,6 +61,7 @@ json.setting do json.common @common json.third_party @third_party + json.third_party_new @third_party_new if @top_system_notification.present? json.system_notification do diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 3eed48c20..543b2249f 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -1,21 +1,27 @@ -OmniAuth.config.add_camelization 'qq', 'QQ' +config = Rails.application.config_for(:configuration) + +OmniAuth.config.add_camelization 'qq', 'QQ' if config.dig("oauth", "qq") +OmniAuth.config.add_camelization 'github', 'GitHub' if config.dig("oauth", "github") +OmniAuth.config.add_camelization 'gitee', 'Gitee' if config.dig("oauth", "gitee") +OmniAuth.config.add_camelization 'wechat', 'Wechat' if config.dig("oauth", "wechat") OmniAuth.config.logger = Rails.logger +OmniAuth.config.before_request_phase = nil +OmniAuth.config.before_callback_phase = nil OmniAuth.config.on_failure = Proc.new { |env| OmniAuth::FailureEndpoint.new(env).redirect_to_failure } -oauth_config = {} -begin - config = Rails.application.config_for(:configuration) - oauth_config = config.dig('oauth', 'qq') - raise 'oauth qq config missing' if oauth_config.blank? -rescue => ex - raise ex if Rails.env.production? - - puts %Q{\033[33m [warning] qq oauth config or configuration.yml missing, - please add it or execute 'cp config/configuration.yml.example config/configuration.yml' \033[0m} -end - Rails.application.config.middleware.use OmniAuth::Builder do - provider :qq, oauth_config['appid'], oauth_config['secret'], { provider_ignores_state: true } + if config.dig("oauth", "qq") + provider :qq, config.dig("oauth", "qq", "appid"), config.dig("oauth", "github", "secret"), { provider_ignores_state: true } + end + if config.dig("oauth", "github").present? + provider :github, config.dig("oauth", "github", "appid"), config.dig("oauth", "github", "secret"), { provider_ignores_state: true, scope: "user:email" } + end + if config.dig("oauth", "gitee").present? + provider :gitee, config.dig("oauth", "gitee", "appid"), config.dig("oauth", "gitee", "secret"), { provider_ignores_state: true, scope: "user_info emails" } + end + if config.dig("oauth", "wechat").present? + provider :gitee, config.dig("oauth", "wechat", "appid"), config.dig("oauth", "wechat", "secret"), { provider_ignores_state: true, scope: "snsapi_login" } + end end diff --git a/config/initializers/per_form_csrf_tokens.rb b/config/initializers/per_form_csrf_tokens.rb new file mode 100644 index 000000000..5afb75e59 --- /dev/null +++ b/config/initializers/per_form_csrf_tokens.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +# Be sure to restart your server when you modify this file. + +# Enable per-form CSRF tokens. +# Rails.application.config.action_controller.per_form_csrf_tokens = true +# Rails.application.config.action_controller.forgery_protection_origin_check = true \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb index f47bd5aba..0efac72c0 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -23,6 +23,7 @@ Rails.application.routes.draw do get 'auth/qq/callback', to: 'oauth/qq#create' get 'auth/failure', to: 'oauth/base#auth_failure' get 'auth/cas/callback', to: 'oauth/cas#create' + get 'auth/:provider/callback', to: 'oauth/callbacks#create' get 'oauth/bind', to: 'oauth/educoder#bind' get 'oauth/register', to: 'oauth#register'