Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ gem 'haml-rails'
gem 'rest-client'
gem 'whenever', require: false
gem 'rack-proxy'
gem 'ipaddress'

#gem 'copycopter_client', '~> 2.0.1'
# Use Capistrano for deployment
Expand Down
49 changes: 28 additions & 21 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ GEM
concurrent-ruby (1.1.10)
crass (1.0.6)
daemons (1.4.1)
date (3.3.3)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
devise (4.8.1)
Expand All @@ -126,17 +127,17 @@ GEM
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
dry-inflector (1.0.0)
erubi (1.11.0)
erubi (1.12.0)
eventmachine (1.2.7)
execjs (2.8.1)
factory_bot (6.2.1)
activesupport (>= 5.0.0)
factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0)
railties (>= 5.0.0)
faker (3.0.0)
faker (3.1.0)
i18n (>= 1.8.11, < 2)
faraday (2.7.1)
faraday (2.7.2)
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday-multipart (1.0.4)
Expand All @@ -150,7 +151,7 @@ GEM
activesupport (>= 5.0)
groupdate (6.1.0)
activesupport (>= 5.2)
haml (6.0.11)
haml (6.1.1)
temple (>= 0.8.2)
thor
tilt
Expand All @@ -165,6 +166,7 @@ GEM
i18n (1.12.0)
concurrent-ruby (~> 1.0)
ice_nine (0.11.2)
ipaddress (0.8.3)
jbuilder (2.11.5)
actionview (>= 5.0.0)
activesupport (>= 5.0.0)
Expand Down Expand Up @@ -194,8 +196,11 @@ GEM
loofah (2.19.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
mail (2.7.1)
mail (2.8.0)
mini_mime (>= 0.1.1)
net-imap
net-pop
net-smtp
marcel (1.0.2)
method_source (1.0.0)
mime-types (3.4.1)
Expand All @@ -208,14 +213,15 @@ GEM
open4 (~> 1.3.4)
rake
mini_mime (1.1.2)
mini_portile2 (2.8.0)
mini_portile2 (2.8.1)
minitest (5.16.3)
multipart-post (2.2.3)
net-imap (0.3.1)
net-imap (0.3.4)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.1.3)
net-protocol (0.2.1)
timeout
net-smtp (0.3.3)
net-protocol
Expand All @@ -237,11 +243,11 @@ GEM
pry (0.14.1)
coderay (~> 1.1)
method_source (~> 1.0)
public_suffix (5.0.0)
puma (6.0.0)
public_suffix (5.0.1)
puma (6.0.1)
nio4r (~> 2.0)
racc (1.6.1)
rack (2.2.4)
racc (1.6.2)
rack (2.2.5)
rack-proxy (0.7.4)
rack
rack-test (2.0.2)
Expand Down Expand Up @@ -295,10 +301,10 @@ GEM
rexml (3.2.5)
rspec-core (3.12.0)
rspec-support (~> 3.12.0)
rspec-expectations (3.12.0)
rspec-expectations (3.12.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-mocks (3.12.0)
rspec-mocks (3.12.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.12.0)
rspec-rails (6.0.1)
Expand All @@ -322,9 +328,9 @@ GEM
sprockets (> 3.0)
sprockets-rails
tilt
shoulda-matchers (5.2.0)
shoulda-matchers (5.3.0)
activesupport (>= 5.2.0)
simplecov (0.21.2)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
simplecov_json_formatter (~> 0.1)
Expand All @@ -337,16 +343,16 @@ GEM
spring-watcher-listen (2.1.0)
listen (>= 2.7, < 4.0)
spring (>= 4)
sprockets (4.1.1)
sprockets (4.2.0)
concurrent-ruby (~> 1.0)
rack (> 1, < 3)
rack (>= 2.2.4, < 4)
sprockets-rails (3.4.2)
actionpack (>= 5.2)
activesupport (>= 5.2)
sprockets (>= 3.0.0)
sqlite3 (1.5.4)
mini_portile2 (~> 2.8.0)
telegram-bot-ruby (0.22.0)
telegram-bot-ruby (0.23.0)
dry-inflector
faraday (~> 2.0)
faraday-multipart (~> 1.0)
Expand All @@ -361,8 +367,8 @@ GEM
thor (1.2.1)
thread_safe (0.3.6)
tilt (2.0.11)
timeout (0.3.0)
tinymce-rails (6.3.0)
timeout (0.3.1)
tinymce-rails (6.3.1)
railties (>= 3.1.1)
tinymce-rails-langs (6.20220429)
tinymce-rails (~> 6.0)
Expand Down Expand Up @@ -417,6 +423,7 @@ DEPENDENCIES
groupdate
haml
haml-rails
ipaddress
jbuilder
jquery-rails
kaminari
Expand Down
1 change: 1 addition & 0 deletions app/controllers/hackers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ def remove_nfc

def edit
@new_public_ssh_key = PublicSshKey.new(user: @user)
@new_wg_config = WgConfig.new(user: @user)
redirect_to root_path, alert: 'Ошибка' unless @user == current_user or current_user.admin?
end

Expand Down
61 changes: 61 additions & 0 deletions app/controllers/wg_configs_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
class WgConfigsController < ApplicationController
load_and_authorize_resource

before_action :set_user, only: [:create, :destroy, :export]
before_action :authenticate_token!, only: [:export_peers]

def create
@wgconfig = WgConfig.new(wg_config_params)

if @wgconfig.save
redirect_to edit_user_path(@user, anchor: 'wg-configs'), notice: "Конфигурация WireGuard создана успешно"
else
redirect_to edit_user_path(@user),
alert: "Ошибка создания конфигурации WireGuard: #{@wgconfig.errors.full_messages.join("\n")}"
end
end

def destroy
wg = @user.wg_configs.find_by(id: params[:id])
wg&.destroy
redirect_to edit_user_path(@user, anchor: 'wg-configs')
end

def export
wg = @user.wg_configs.find_by(id: params[:id])

if wg
send_data wg.to_s, filename: "wg-hackerspace-#{wg.name}.conf", type: "text/plain"
else
redirect_to user_path(@user), alert: "Конфигурация WireGuard не найдена"
end
end

def export_peers
wgs = WgConfig.order(:user_id).select { |wg| wg.user.active? }

peers_config = wgs.map { |wg| wg.as_peer }.join("\n\n")

render plain: peers_config
end

private

def authenticate_token!
token = request.headers['Authorization']&.split&.last
if not ActiveSupport::SecurityUtils.secure_compare(token || '', Rails.application.secrets.wireguard_token) then
render plain: "Authorization required\n", status: :unauthorized
end
end

def wg_config_params
params.require(:wg_config).permit(
:name,
:user_id
)
end

def set_user
@user = User.find(params[:user_id])
end
end
3 changes: 3 additions & 0 deletions app/models/ability.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ def initialize(user)

can [:ssh_keys, :detected_at_hackerspace, :find_by_mac, :useful], User

can [:export_peers], WgConfig

if user.present?
can :chart, :main
can :image, :uploader
Expand All @@ -60,6 +62,7 @@ def initialize(user)
can :manage, Mac, user_id: user.id
can :manage, NfcKey, user_id: user.id
can :manage, PublicSshKey, user_id: user.id
can :manage, WgConfig, user_id: user.id

can :read, Device
can :add, Event
Expand Down
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ class User < ApplicationRecord
has_many :payments
has_many :nfc_keys
has_many :public_ssh_keys
has_many :wg_configs
belongs_to :tariff
belongs_to :guarantor1, class_name: 'User', optional: true
belongs_to :guarantor2, class_name: 'User', optional: true
Expand Down
81 changes: 81 additions & 0 deletions app/models/wg_config.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
require 'ipaddress'
require 'open3'

class WgConfig < ApplicationRecord

belongs_to :user

validates :name, presence: true
validates :privatekey, presence: true
validates :publickey, presence: true
validates :name, uniqueness: { scope: :user_id }

after_initialize :init_keys

def generate_keys!
self.privatekey = gen_privatekey
self.publickey = gen_publickey(self.privatekey)
end

def addresses(as_networks=true)
raise "Model is not saved" if self.id.nil?

first = IPAddress Setting['wgFirstClientAddress']
last = IPAddress Setting['wgLastClientAddress']

ip = IPAddress(first.to_i + self.id)

raise "Failed to assign IP: out of range" if ip > last

ip.netmask = Setting['wgNetmask'] if as_networks

ip.to_string
end

def to_s
lines = []
lines << "# WireGuard config #{name}"
lines << '[Interface]'
lines << "PrivateKey = #{privatekey}"
lines << "Address = #{self.addresses}"
lines << ''
lines << '[Peer]'
lines << "PublicKey = #{Setting['wgServerPublicKey']}"
lines << "Endpoint = #{Setting['wgServerEndpoint']}"
lines << "AllowedIPs = #{Setting['wgAllowedIPs']}"

lines.join("\n")
end

def as_peer
s = []
s << "# User #{self.user_id}, config '#{self.name}'"
s << "[Peer]"
s << "PublicKey = #{publickey}"
s << "AllowedIPs = #{addresses(false)}"

s.join("\n")
end

private

def init_keys
generate_keys! if self.privatekey.blank?
end

def gen_privatekey
key, status = Open3.capture2("wg genkey")
key.strip
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we had to call external programs here, I would just wrap the whole thing in shell script, so that it could run independently of Ruby.


def gen_publickey(private_key)
stdout_str = ''
Open3.popen2("wg pubkey") do |stdin, stdout, _wait_thr|
stdin.print(private_key)
stdin.close
stdout_str = stdout.gets
end

stdout_str.strip
end
end
23 changes: 23 additions & 0 deletions app/views/hackers/_form.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,26 @@
.form-group
= submit_tag('Добавить публичный SSH ключ', class: 'btn btn-primary')

-# WireGuard
%hr
.row#wg-configs
.col-lg-6
- unless @user.wg_configs.empty?
%h3 Конфигурации WireGuard
- @user.wg_configs.each do |wg|
.row.small
.col-lg-4
%p
= wg.name
.col-lg-1
%p
= link_to 'Удалить', user_wg_config_path(@user, wg), method: :delete, data: { confirm: 'Вы уверены?' }

.row
.col-lg-6
= form_for [@user, @new_wg_config] do |f|
= f.hidden_field :user_id
.form-group
= f.text_field :name, class: 'form-control'
.form-group
= submit_tag('Создать конфигурацию WireGuard', class: 'btn btn-primary')
11 changes: 11 additions & 0 deletions app/views/hackers/show.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,14 @@
%h4= t('users.public_ssh_keys') + ':'
- @user.public_ssh_keys.each do |public_ssh_key|
.ssh-public-key= public_ssh_key.body

-if @user.wg_configs.any?
.row.additional_info
.col-md-8
%h4= t('users.wg_configs') + ':'
- @user.wg_configs.each do |wg|
.wg_config.row
.col-lg-3
= wg.name
.col-lg-2
= link_to 'Скачать', user_wg_export_path(@user, wg), method: :post
1 change: 1 addition & 0 deletions config/locales/ru.yml
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ ru:
telegram_username: Telegram
github_username: Github
public_ssh_keys: Public SSH keys
wg_configs: Конфигурации WireGuard
last_payment_ended_at: Оплачено по
last_seen_in_hackerspace: Видели в ХС
learner: Курсант
Expand Down
Loading