| @@ -1,4 +1,6 @@ | |||
| require 'oauth2' | |||
| # require 'openssl' | |||
| # require 'jwt' | |||
| class ApplicationController < ActionController::Base | |||
| include CodeExample | |||
| @@ -295,17 +297,24 @@ class ApplicationController < ActionController::Base | |||
| # Find the current user | |||
| #Rails.logger.info("current_laboratory is #{current_laboratory} domain is #{request.subdomain}") | |||
| if request.headers["Authorization"].present? && request.headers["Authorization"].start_with?('Bearer') | |||
| tip_exception(401, "请登录后再操作!") unless valid_doorkeeper_token? | |||
| if @doorkeeper_token.present? | |||
| # client方法对接,需要一直带着用户标识uid | |||
| if @doorkeeper_token.resource_owner_id.blank? | |||
| tip_exception(-1, "缺少用户标识!") if params[:uid].nil? | |||
| User.current = User.find(params[:uid]) | |||
| else | |||
| User.current = User.find_by(id: @doorkeeper_token.resource_owner_id) | |||
| if !valid_doorkeeper_token? | |||
| header = request.authorization | |||
| pattern = /^Bearer /i | |||
| token = header.gsub(pattern, "") | |||
| User.current, message = Bot.decode_jwt_token(token) | |||
| tip_exception(401, message) if message.present? | |||
| else | |||
| if @doorkeeper_token.present? | |||
| # client方法对接,需要一直带着用户标识uid | |||
| if @doorkeeper_token.resource_owner_id.blank? | |||
| tip_exception(-1, "缺少用户标识!") if params[:uid].nil? | |||
| User.current = User.find(params[:uid]) | |||
| else | |||
| User.current = User.find_by(id: @doorkeeper_token.resource_owner_id) | |||
| end | |||
| end | |||
| end | |||
| else | |||
| else | |||
| User.current = find_current_user | |||
| uid_logger("user_setup: " + (User.current.logged? ? "#{User.current.try(:login)} (id=#{User.current.try(:id)})" : "anonymous")) | |||
| @@ -0,0 +1,46 @@ | |||
| class InstallationsController < ApplicationController | |||
| include RegisterHelper | |||
| before_action :require_login | |||
| def index | |||
| @install_bots = BotInstall.where(:installer_id => current_user.id) | |||
| end | |||
| def register | |||
| @bot = Bot.find params[:id] | |||
| @bot.client_id = Doorkeeper::OAuth::Helpers::UniqueToken.generate if params[:client_id].blank? | |||
| @bot.client_secret = Doorkeeper::OAuth::Helpers::UniqueToken.generate if params[:client_secret].blank? | |||
| @bot.private_key = OpenSSL::PKey::RSA::generate(2048).to_s | |||
| @bot.owner_id = current_user.id | |||
| ActiveRecord::Base.transaction do | |||
| # 注册bot对应oauth应用 | |||
| Doorkeeper::Application.create!(name: @bot.name, uid: @bot.client_id, secret: @bot.client_secret, redirect_uri: "https://gitlink.org.cn") | |||
| # 注册bot对应用户 | |||
| result = autologin_register(User.generate_user_login('b'), nil, "b58333123413", 'bot', nickname: @bot.name) | |||
| tip_exception(-1, result[:message]) if result[:message].present? | |||
| @bot.uid = result[:user][:id] | |||
| @bot.save | |||
| render_ok | |||
| rescue Exception => e | |||
| tip_exception(-1, e.message) | |||
| end | |||
| end | |||
| def access_tokens | |||
| @install_bot = BotInstall.find params[:id] | |||
| @bot = @install_bot.bot | |||
| @application = Doorkeeper::Application.find_by(uid: @bot.client_id, secret: @bot.client_secret) | |||
| if @application.present? | |||
| # 给bot生成token,因为bot是机器人操作 | |||
| @access_token = Doorkeeper::AccessToken.create!({ :application_id => @application.id, | |||
| :resource_owner_id => @bot.uid, | |||
| :scopes => "public write", | |||
| :expires_in => "604800", | |||
| :use_refresh_token => true | |||
| }) | |||
| end | |||
| render_ok(token: @access_token.token) | |||
| end | |||
| end | |||
| @@ -0,0 +1,51 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: bot | |||
| # | |||
| # id :integer not null, primary key | |||
| # bot_name :string(255) | |||
| # bot_des :text(4294967295) | |||
| # webhook :string(255) | |||
| # is_public :integer | |||
| # logo :string(255) | |||
| # state :integer | |||
| # client_id :string(255) | |||
| # client_secret :string(255) | |||
| # web_url :string(255) | |||
| # category :string(255) | |||
| # install_num :integer default("0") | |||
| # update_time :datetime not null | |||
| # create_time :datetime not null | |||
| # private_key :text(65535) | |||
| # uid :integer | |||
| # owner_id :integer | |||
| # | |||
| # Indexes | |||
| # | |||
| # name (bot_name) UNIQUE | |||
| # | |||
| class Bot < ApplicationRecord | |||
| self.table_name = "bot" | |||
| has_many :install_bots | |||
| def name | |||
| self.bot_name | |||
| end | |||
| def self.decode_jwt_token(token) | |||
| decoded_token = JWT.decode token, nil, false | |||
| return [nil, "Token已过期"] if Time.now.to_i - 60 - decoded_token[0]["exp"].to_i > 0 | |||
| bot = Bot.find_by(id: decoded_token[0]["iss"]) | |||
| return [nil, "Token不存在"] if bot.blank? | |||
| rsa_private = OpenSSL::PKey::RSA.new(bot.private_key) | |||
| rsa_public = rsa_private.public_key | |||
| JWT.decode token, rsa_public, true, { algorithm: 'RS256' } | |||
| [User.find_by(id: bot.owner_id), ""] | |||
| rescue JWT::DecodeError | |||
| Rails.logger.error "jwt token decode error:#{token}" | |||
| [nil, "无效Token"] | |||
| end | |||
| end | |||
| @@ -0,0 +1,20 @@ | |||
| # == Schema Information | |||
| # | |||
| # Table name: install_bot | |||
| # | |||
| # id :integer not null, primary key | |||
| # bot_id :integer not null | |||
| # installer_id :integer not null | |||
| # store_id :integer not null | |||
| # state :integer not null | |||
| # create_time :datetime not null | |||
| # update_time :datetime not null | |||
| # | |||
| # frozen_string_literal: true | |||
| class BotInstall < ApplicationRecord | |||
| self.table_name = "install_bot" | |||
| belongs_to :bot | |||
| end | |||
| @@ -114,7 +114,7 @@ class User < Owner | |||
| # trustie: 来自Trustie平台 | |||
| # forge: 平台本身注册的用户 | |||
| # military: 军科的用户 | |||
| enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat], default: :forge, scope: :shallow | |||
| enumerize :platform, in: [:forge, :educoder, :trustie, :military, :github, :gitee, :qq, :wechat, :bot], default: :forge, scope: :shallow | |||
| belongs_to :laboratory, optional: true | |||
| has_one :user_extension, dependent: :destroy | |||
| @@ -0,0 +1,7 @@ | |||
| json.status 0 | |||
| json.message "success" | |||
| json.data do | |||
| json.array! @install_bots do |install_bot| | |||
| json.extract! install_bot.bot, :id, :name | |||
| end | |||
| end | |||
| @@ -18,7 +18,7 @@ Doorkeeper.configure do | |||
| User.authenticate!(params[:username], params[:password]) | |||
| end | |||
| access_token_generator '::Doorkeeper::JWT' | |||
| # access_token_generator '::Doorkeeper::JWT' | |||
| admin_authenticator do | |||
| user = current_user | |||
| @@ -1047,6 +1047,17 @@ Rails.application.routes.draw do | |||
| resources :commit_logs, :only => [:create] | |||
| scope '/app' do | |||
| post 'register', to: 'installations#register' | |||
| resources :installations do | |||
| get :repositories, on: :collection | |||
| member do | |||
| post :access_tokens | |||
| put :suspended | |||
| end | |||
| end | |||
| end | |||
| root 'main#index' | |||
| @@ -0,0 +1,9 @@ | |||
| class AddBotInfo < ActiveRecord::Migration[5.2] | |||
| def change | |||
| if table_exists? :bot | |||
| add_column :bot, :private_key, :text, comment: "私钥" | |||
| add_column :bot, :owner_id, :integer, comment: "所有者ID" | |||
| add_column :bot, :uid, :integer, comment: "Bot机器人用户ID" | |||
| end | |||
| end | |||
| end | |||
| @@ -0,0 +1,42 @@ | |||
| require 'openssl' | |||
| require 'jwt' # https://rubygems.org/gems/jwt | |||
| # Private key contents | |||
| private_pem = File.read("/Users/xxq/Documents/gitlink-webhook.2022-06-09.private-key.pem") | |||
| private_key22="-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEApOebWmRV/ooNq5Ks04YnDU7pEezGShGvaiF0cIvn9jvmYHu0\nFialojvJV3VpB6xE6QBPXZ0Pi1lokZ9dMx8F5UWNx9WA7wf7xK3hAJLNml+GeewF\nou8vk/Ry7n6diLxETNVd7YzPvztn5qaMp/DXa+65i11H8a/XXqR7kCVnCevVlufh\nNr/Dp6dW31W8TInnDQasJFMZ8GY7f+tCwLXNc0M8p+TeDp9xmXHOrEB+S/mgbUOF\nXgRr6icbMmlT9bsAxYHrrDkcVxJhs0hq5vD3BaoK06gcZEnN7/HVNzgVSOYNsVNh\n9006cMgDSOwc9F8aulP7cr8k74INq1xswoGs9wIDAQABAoIBAHayc2NkF3YJXv+h\nqx7yUEfHBgKuAKiuBCqLfCnKuqPFx/So9h5/oPeeuzVlwL0SJePlIjuK4vZ128v9\n/vLeILtADmbJ6m2jvHh8hBmKkc3Ndplp50C5k/CWoufCYZhbk3oOlvZ3Rc4rb4VZ\nWqNDu3voMMv8z91KqeZo1LwUAA/l9mU++zLkRA6qOuWGBJFsM8YpshzxL5lzRUb3\n7y+YJDyUZztfzKwr6pqm1n9B2e6e+znCw1vMZXp2TbUrpvrrXSxlgdNuK68SkZX6\nTdZUD8y0viwaioRVf3vR+e/Bf7yZannGdvcmVGs0A7dq9QgHkakqNHiRkQgwviSq\nbjBo7dECgYEAzekeP5j/dAPkv9X4qnmZ4du/+ZgrQrJckDD/JuNIBmQT9m286l4P\nmb2TBcWkswVOZaS5Qy2bN/69rwIbcdvbaROGBCabn3ATK4fSzmUk31M2rRKYZqaU\nMi0W2g2YtSRg+bV6S7aFXa98j5+JlqJeDZQoRuvL68ooq5WzFWmfYnkCgYEAzQTi\n4USqz2z66BfU+v2rchzK8URxnv7EW/CG3XFRsG+1UXCyEIct2L7rzvC7r7+jjS4s\ngmV3Civ1sckGMwikLzxFtUZ1LUBakZp/mmipIzxcHOeBsRdHei8BFvMNqveg1JpO\ncY/Fp+wEkSNLhfkb/IXRw0iwFalBRnyo4BJbLu8CgYBrQ7E6OB169jxHotNzGv2K\npssO3rJKgFev1ZZVT7jJe4Dasrfi7zT5RcQ9EYSGrZD1aiYIVM2zEcUGUfayDXHy\n/vSlXOdc2ylhV9P9KLtYiyTEbBdwAf7ZVJu+465VTqol6t/WaTJ4Z15gAx/NlK+i\nKzgAGf2Uyy78k3NDCE67IQKBgFwM0pUUEKEbLDhi4uRiWsTcep4C/gTGHIGvJ85r\nH6NZNI7BS6GyH/qOFjAO1CYfpB4yWhed2Om/PQw61sa5HYZ7yEyQuvG7UC7JsHsy\nfKZuZmkv5IIPkq8gRZv5OuzFS/fI5GmGhNdVV+OWdkVLyK4Do1/L1guTt9QfCm+4\nrioPAoGBALGr8aUAbz/A611M/bLnk04UYfV+M34/hCf6/rKiBHdQoIHOriSC9Nv7\nyhE5axTdmIWMxfbyb3vHJ5MizZkD/Qj0VDuMkyS2+3TepI6tySQE3YQeWnCMJI9i\nuoCZ31GBui4+W5udbx8NOVsJfXUQn/OAoOn6WuMNPdgB45KXcktj\n-----END RSA PRIVATE KEY-----\n" | |||
| private_key33= "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAq/wUH8N+5fzj3hArKY7ChC591R/uKyeNM/BbsR2OGxO5F1CE\nozy6thtPult96Gm9oK3sMpLdYCze2YgozgteFO1Ft0o1GEJ1A4SinOKzeixLpFy0\n5N9t+iz7Xa7jC/1E3uy/s2WvSYCS9NnK2Uj3DQOH8BUWfkvyTtt91a2pplbPCV3T\nw1PykAcDWIFXVJJCMtYd2x+DukSWKHRsYbBCMtVZhEVuKmTE3FBTDVu9sN3b7uLL\n5RzHUg13QZZr9OvMNR3nUZl6yDxw+wD4anDrtpL9C+tFjhMyqsyYpYWwcJm65YiD\ny7Ps24IdcLB4iOxJE91fu+MnicvyBrtEjoBP/wIDAQABAoIBAAcKc9x1CW3q8300\n1j+GS6pTqO0fuIVlwh8dOPPATQAIx6wPrM5t/wrThWkQs8/e/Fdmp2POpWd5jsoD\nDACbcIeUyyTc0d2jYtz5AhtAIK7gv1wEO5efGgaC7ut/7GWiQb6KnLKAeDOfIuUJ\nQYexuAN9YIRQqLIU89+MltM3n9liZTMuPWRFJcitaDytXa10TCe5RUqHGZf49pi7\njCgk0x7jDYqbIzsqOu741P8My/gkAjKPkRnjaj3o6MrwHzIlc4t/6mKbaPnywywk\n6roYMqmytgueA9wxFcj74ekBQAaXsu4xRkbZXxjcBtIvTId5IHHK5Z/r3fgE9K3J\nOuzzJ1kCgYEA3uu/pUjJbKegOsgSdu3cO/NvRV2YsRD4NUgtiMCEakE4VQXRK5pf\nV8xqQeH/rLjZf5aP5xe8n25krh/c+m0ezOMyu5MmhoxaWCPWIezsaKJXOcvsOxIu\n2sJ9GRMXabyuDuSdL7ZGYMpLhRclXYLyPCz7wzN445IluTHuD3lJ2qUCgYEAxYFh\ncVD73yNZn9BN1DSGWpfPtLqOKIdG+xi/ypCSGpJG0QCJRFi7R1qJOxFtJNI8DRiD\nZapPEGLVd/KY5NzBGZBfNQt4DQH9qR4l43c6NNkisWA9rvXvCDqXKmBq7wfpnkYr\n4Ul2hXYmsPJjP8e0BfG54PaSu3BDBMJMtcgDktMCgYBvzyDdnwdgVyc3tHgGbMFk\n1HHAAfT/ArrrxpsIFz+TJ8lAY92JGDGwENhO2TLrCAAXTYY5657w/GbFKzgj5y1m\nqKIekOzm2WjLApZ5h6L/zEUhuRVwf2s+0AP82qWIpFlNIP9yGeNs0qpUQ8q6/13O\nLuXL/3on8nq3S8LSwgv3/QKBgDfM+g7d5ouAnU29uH9/54Wo5pIVMxzYO4Gt2GIO\nvnirYz6hfCbHOwJJ3gPGRKPmkfjROC59E6F5iv48mF3w0M28MGn4N47VRSmGzwWZ\nJeTQhDDBFCxeZ45Xn2Xln9Cw15xUDwmzi7zhSMUtdkUK0x3q0a1xfLtgWE775lhl\njjzpAoGAdUXFW1elfjXpfIYZf7vUV7MPquKL7qAcopd96XBszhOn7g+ibzem+wgt\n1UTSeOBESYANHeJk2MuWPSRXk/FlQETVIcPAEp0kxbwQE+7YEdrMVeDcIe5lPwGD\n+WuS3kg0MPgUrXZXn74gcwWmSIOyHfqXULqOxWE25uU2icdV+2w=\n-----END RSA PRIVATE KEY-----\n" | |||
| private_key = OpenSSL::PKey::RSA.new(private_key33) | |||
| # puts private_key.to_json | |||
| # Generate the JWT | |||
| payload = { | |||
| # issued at time, 60 seconds in the past to allow for clock drift | |||
| iat: Time.now.to_i - 60, | |||
| # JWT expiration time (10 minute maximum) | |||
| exp: Time.now.to_i + (10 * 60), | |||
| # GitHub App's identifier | |||
| iss: "782" | |||
| } | |||
| jwt = JWT.encode(payload, private_key, "RS256") | |||
| puts jwt | |||
| # puts OpenSSL::PKey::RSA.new(private_key33).public_key.to_s | |||
| # | |||
| rsa_private = OpenSSL::PKey::RSA.new(private_key33) | |||
| rsa_public = rsa_private.public_key | |||
| # decoded_token = JWT.decode jwt, nil, false | |||
| begin | |||
| decoded_token = JWT.decode jwt, rsa_private, true, { algorithm: 'RS256' } | |||
| rescue JWT::DecodeError | |||
| puts "jwt is not mmmmmm" | |||
| end | |||
| # | |||
| puts decoded_token[0] | |||
| puts decoded_token[0]["iss"] | |||
| # serialized_private_key = OpenSSL::PKey::RSA::generate(2048).to_s | |||