diff --git a/app/controllers/accounts_controller.rb b/app/controllers/accounts_controller.rb index e0508efe8..119812225 100644 --- a/app/controllers/accounts_controller.rb +++ b/app/controllers/accounts_controller.rb @@ -1,6 +1,7 @@ class AccountsController < ApplicationController before_action :require_login, only: [:login_check, :simple_update, :change_password] include ApplicationHelper + include AesCryptHelper #skip_before_action :check_account, :only => [:logout] @@ -143,7 +144,8 @@ class AccountsController < ApplicationController user = Users::RegisterService.call(register_params) user.mail = "#{user.login}@example.org" if user.mail.blank? - password = register_params[:password].strip + password = decrypt(register_params[:password]) rescue "" + password = password.strip # gitea用户注册, email, username, password interactor = Gitea::RegisterInteractor.call({username: user.login, email: user.mail, password: password}) @@ -193,8 +195,9 @@ class AccountsController < ApplicationController # 用户登录 def login - Users::LoginForm.new(login_params).validate! - @user = User.try_to_login(params[:login], params[:password]) + password = decrypt(login_params[:password]) rescue "" + Users::LoginForm.new(login_params.merge!({password: password})).validate! + @user = User.try_to_login(params[:login], password) return normal_status(-2, "错误的账号或密码") if @user.blank? # user is already in local database @@ -203,7 +206,7 @@ class AccountsController < ApplicationController login_control = LimitForbidControl::UserLogin.new(@user) return normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") if login_control.forbid? - password_ok = @user.check_password?(params[:password].to_s) + password_ok = @user.check_password?(password.to_s) unless password_ok if login_control.remain_times-1 == 0 normal_status(-2, "登录密码出错已达上限,账号已被锁定,请#{login_control.forbid_expires/60}分钟后重新登录或找回密码") @@ -216,21 +219,24 @@ class AccountsController < ApplicationController LimitForbidControl::UserLogin.new(@user).clear successful_authentication(@user) - sync_pwd_to_gitea!(@user, {password: params[:password].to_s}) # TODO用户密码未同步 + sync_pwd_to_gitea!(@user, {password: password.to_s}) # TODO用户密码未同步 # session[:user_id] = @user.id end def change_password - return render_error("两次输入的密码不一致") if params[:password].to_s != params[:new_password_repeat].to_s + password = decrypt(params[:password]) rescue "" + new_password_repeat = decrypt(params[:new_password_repeat]) rescue "" + old_password = decrypt(params[:old_password]) rescue "" + return render_error("两次输入的密码不一致") if password.to_s != new_password_repeat.to_s @user = User.find_by(login: params[:login]) return render_forbidden unless User.current.login == @user&.login return render_error("此用户禁止修改密码!") if @user.id.to_i === 104691 return render_error("未找到相关用户!") if @user.blank? - return render_error("旧密码不正确") unless @user.check_password?(params[:old_password]) + return render_error("旧密码不正确") unless @user.check_password?(old_password) sync_params = { - password: params[:password].to_s, + password: password.to_s, email: @user.mail, login_name: @user.name, source_id: 0 @@ -238,7 +244,7 @@ class AccountsController < ApplicationController interactor = Gitea::User::UpdateInteractor.call(@user.login, sync_params) if interactor.success? - @user.update_attribute(:password, params[:password]) + @user.update_attribute(:password, password) render_ok else render_error(interactor.error) diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 09c5a3276..676304917 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -1,4 +1,5 @@ class Api::V1::UsersController < Api::V1::BaseController + include AesCryptHelper before_action :load_observe_user, except: [:check_user_id, :check_user_login] before_action :check_auth_for_observe_user, except: [:check_user_id, :check_user_login] @@ -53,7 +54,7 @@ class Api::V1::UsersController < Api::V1::BaseController end def check_password - password = params[:password] + password = decrypt(params[:password]) rescue "" return tip_exception(-5, "8~16位密码,支持字母数字和符号") unless password =~ CustomRegexp::PASSWORD return tip_exception(-5, "密码错误") unless @observe_user.check_password?(password) render_ok @@ -126,7 +127,8 @@ class Api::V1::UsersController < Api::V1::BaseController def destroy - return tip_exception(-1, "密码不正确.") unless @observe_user.check_password?(params[:password]) + password = decrypt(params[:password]) rescue "" + return tip_exception(-1, "密码不正确.") unless @observe_user.check_password?(password) org_ids = TeamUser.where(user_id: @observe_user.id).pluck(:organization_id) | OrganizationUser.where(user_id: @observe_user.id).pluck(:organization_id) org_count = TeamUser.where(organization_id: org_ids).where(user_id: @observe_user.id).joins(:team).where(teams: {authorize: %w(owner)}).count project_count = Project.where(user_id: @observe_user.id).count diff --git a/app/controllers/organizations/organizations_controller.rb b/app/controllers/organizations/organizations_controller.rb index 3c4e64780..6cedea496 100644 --- a/app/controllers/organizations/organizations_controller.rb +++ b/app/controllers/organizations/organizations_controller.rb @@ -1,4 +1,5 @@ class Organizations::OrganizationsController < Organizations::BaseController + include AesCryptHelper before_action :require_login, except: [:index, :show, :recommend, :languages] # before_action :require_profile_completed, only: [:create] before_action :convert_image!, only: [:create, :update] @@ -139,7 +140,7 @@ class Organizations::OrganizationsController < Organizations::BaseController end def password - params.fetch(:password, "") + decrypt(params[:password]) rescue "" end def load_organization diff --git a/app/forms/base_form.rb b/app/forms/base_form.rb index 19af61026..eb00ec562 100644 --- a/app/forms/base_form.rb +++ b/app/forms/base_form.rb @@ -1,5 +1,6 @@ class BaseForm include ActiveModel::Model + include AesCryptHelper Error = Class.new(StandardError) EmailError = Class.new(Error) @@ -53,11 +54,15 @@ class BaseForm end def check_password(password) + password = decrypt(password) rescue "" password = strip(password) raise PasswordFormatError, "密码8~16位密码,支持字母数字和符号" unless password =~ CustomRegexp::PASSWORD end def check_password_confirmation(password, password_confirmation) + password = decrypt(password) rescue "" + password_confirmation = decrypt(password_confirmation) rescue "" + password = strip(password) password_confirmation = strip(password_confirmation) diff --git a/app/helpers/aes_crypt_helper.rb b/app/helpers/aes_crypt_helper.rb new file mode 100644 index 000000000..798c6dd61 --- /dev/null +++ b/app/helpers/aes_crypt_helper.rb @@ -0,0 +1,45 @@ +module AesCryptHelper + + AES_KEY = EduSetting.get("login_crypt_key") || '59c96c3572ab8cc1' + + def encrypt(plain_text, output_encoding = 'base64') + + # 将字符串密钥和IV转换为16字节的字节数组 + key = AES_KEY.byteslice(0, 16) + iv = AES_KEY.byteslice(0, 16) + + # 创建并设置AES-CBC加密器 + cipher = OpenSSL::Cipher.new('AES-128-CBC') + cipher.encrypt + cipher.key = key + cipher.iv = iv + + # 加密数据,并添加PKCS7填充 + encrypted_data = cipher.update(plain_text) + cipher.final + # 将加密数据转换为Base64编码 + Base64.strict_encode64(encrypted_data) + end + + def decrypt(cipher_text, input_encoding = 'base64') + # 确保密钥是16字节长 + key = AES_KEY.byteslice(0, 16) # 如果密钥不足16字节,填充空格;如果超过,截断 + iv = AES_KEY.byteslice(0, 16) + + decipher = OpenSSL::Cipher.new('AES-128-CBC') + decipher.decrypt + decipher.key = key + decipher.iv = iv + + # 根据输入编码解码密文 + decrypted_data = case input_encoding + when 'base64' + Base64.strict_decode64(cipher_text) + else + cipher_text + end + + decrypted = decipher.update(decrypted_data) + decipher.final + decrypted + end + +end \ No newline at end of file diff --git a/app/jobs/change_issue_status_by_message_job.rb b/app/jobs/change_issue_status_by_message_job.rb index 5fa970c14..b2ded7dec 100644 --- a/app/jobs/change_issue_status_by_message_job.rb +++ b/app/jobs/change_issue_status_by_message_job.rb @@ -9,17 +9,16 @@ class ChangeIssueStatusByMessageJob < ApplicationJob def get_pm_issue_data(user, org, pm_project_id, issue_id) - url = URI("#{EduSetting.get("pms_server_url")}/api/pms/#{org.login}/pmsProjectIssues/#{issue_id}?pmProjectId=#{pm_project_id}") + url = "#{EduSetting.get("pms_server_url")}/api/pms/#{org.login}/pmsProjectIssues/#{issue_id}?pmProjectId=#{pm_project_id}" + headers = { + 'Cookie' => "autologin_trustie=#{Token.get_or_create_permanent_login_token(user, 'autologin')&.value}", + } + + response = RestClient.get(url, headers) - https = Net::HTTP.new(url.host, url.port) - https.use_ssl = true - request = Net::HTTP::Get.new(url) - request["Cookie"] = "autologin_trustie=#{Token.get_or_create_permanent_login_token(user, 'autologin')&.value}" - response = https.request(request) - - puts response.read_body - return JSON.parse(response.read_body)['code'].to_i == 200 + puts response.body + return JSON.parse(response.body)["code"].to_i == 200 rescue return false end @@ -33,6 +32,7 @@ class ChangeIssueStatusByMessageJob < ApplicationJob issue = project.issues.issue_issue.where(project_issues_index: issue_id).where.not(id: issue_id).take || Issue.issue_issue.find_by_id(issue_id) next unless issue.present? # issue不存在 跳过 next if issue.project.present? && !issue.project.member?(user) # issue归属项目,用户没有修改issue的权限,跳过 + next if issue.pm_project_id.nil? && project.id.to_i != issue.project&.id.to_i next if issue.pm_project_id.present? && !get_pm_issue_data(user, project.owner, issue.pm_project_id, issue.id) # issue是组织下工作项,不具备组织的访问权限,跳过 issue_project = issue.project || Project.new(id: 0, user_id: 0, name: 'pm_mm', identifier: 'pm_mm', is_public:true) diff --git a/app/models/edu_setting.rb b/app/models/edu_setting.rb index f4a89c09b..708aa625e 100644 --- a/app/models/edu_setting.rb +++ b/app/models/edu_setting.rb @@ -1,22 +1,23 @@ -# == Schema Information -# -# Table name: edu_settings -# -# id :integer not null, primary key -# name :string(255) -# value :string(255) -# created_at :datetime not null -# updated_at :datetime not null -# description :string(255) -# -# Indexes -# -# index_edu_settings_on_name (name) UNIQUE -# - +# == Schema Information +# +# Table name: edu_settings +# +# id :integer not null, primary key +# name :string(255) +# value :string(255) +# created_at :datetime not null +# updated_at :datetime not null +# description :string(255) +# +# Indexes +# +# index_edu_settings_on_name (name) UNIQUE +# + class EduSetting < ApplicationRecord - after_commit :expire_value_cache + after_commit :expire_value_cache, on: [:create, :update] + after_commit :clear_value_cache, on: :destroy scope :by_search, -> (keyword){ where("name LIKE :keyword OR value LIKE :keyword", keyword: "%#{strip_param(keyword)}%") unless strip_param(keyword).blank? } @@ -25,7 +26,11 @@ class EduSetting < ApplicationRecord end def self.get(key) - Rails.cache.fetch(value_cache_key(key), expires_in: 1.days) do + begin + Rails.cache.fetch(value_cache_key(key), expires_in: 1.days) do + find_by_name(key.to_s)&.value + end + rescue Exception => e find_by_name(key.to_s)&.value end end @@ -41,4 +46,8 @@ class EduSetting < ApplicationRecord def expire_value_cache Rails.cache.write(value_cache_key, value) end + + def clear_value_cache + Rails.cache.delete(value_cache_key) + end end diff --git a/app/services/accounts/reset_password_service.rb b/app/services/accounts/reset_password_service.rb index 5202fe77a..58d0fda8b 100644 --- a/app/services/accounts/reset_password_service.rb +++ b/app/services/accounts/reset_password_service.rb @@ -1,10 +1,11 @@ module Accounts class ResetPasswordService < ApplicationService + include AesCryptHelper # login、code、password、password_confirmation def initialize(user, params) @user = user - @password = params[:password] - @password_confirmation = params[:password_confirmation] + @password = decrypt(params[:password]) rescue "" + @password_confirmation = decrypt(params[:password_confirmation]) rescue "" end def call diff --git a/app/services/api/v1/users/update_email_service.rb b/app/services/api/v1/users/update_email_service.rb index 7ed5a0fbc..3f0875d8a 100644 --- a/app/services/api/v1/users/update_email_service.rb +++ b/app/services/api/v1/users/update_email_service.rb @@ -1,5 +1,6 @@ class Api::V1::Users::UpdateEmailService < ApplicationService include ActiveModel::Model + include AesCryptHelper attr_reader :user, :token, :password, :mail, :old_mail, :code, :verify_code attr_accessor :gitea_data @@ -10,7 +11,7 @@ class Api::V1::Users::UpdateEmailService < ApplicationService def initialize(user, params, token =nil) @user = user @token = token - @password = params[:password] + @password = decrypt(params[:password]) rescue "" @mail = params[:email] @old_mail = user.mail @code = params[:code] diff --git a/app/services/api/v1/users/update_phone_service.rb b/app/services/api/v1/users/update_phone_service.rb index ed53d7eb5..b79387773 100644 --- a/app/services/api/v1/users/update_phone_service.rb +++ b/app/services/api/v1/users/update_phone_service.rb @@ -1,5 +1,6 @@ class Api::V1::Users::UpdatePhoneService < ApplicationService include ActiveModel::Model + include AesCryptHelper attr_reader :user, :password, :phone, :code, :verify_code @@ -8,7 +9,7 @@ class Api::V1::Users::UpdatePhoneService < ApplicationService def initialize(user, params) @user = user - @password = params[:password] + @password = decrypt(params[:password]) rescue "" @phone = params[:phone] @code = params[:code] @verify_code = VerificationCode.where(phone: @phone, code_type: 4).last diff --git a/app/services/users/register_service.rb b/app/services/users/register_service.rb index fc0e4231e..f6c8c2cf2 100644 --- a/app/services/users/register_service.rb +++ b/app/services/users/register_service.rb @@ -1,8 +1,10 @@ class Users::RegisterService < ApplicationService + include AesCryptHelper + def initialize(params) @login = params[:login] @namespace = params[:namespace] - @password = params[:password] + @password = decrypt(params[:password]) rescue "" @code = params[:code] end