Skip to content

Commit d8bec71

Browse files
noshutdown-ru-userleandrogehlenoivanenkoAizeLeOuf
authored
Development (#55)
* added validation of encryption key length (#49) * Update pt-BR.yml (#50) * Update pt-BR.yml * New import feature: update existing keys by name instead of create new ones (and double it) (#53) * Windows specific bugs (#52) * Temporary file should be closed before opening as zip archive, otherwise EAccess Permission Denied will be raised * Content of zip archive should be read as binary before sending as response or it will be corrupted * Add group support in whitelist (#51) * Check if current user linked to group with whitelist * Update select to show groups and list first them before users * set new version * #54 * change code formating * #47 * added French added Japanese * fix tests * update travis * fix * set 2.3.3 Co-authored-by: Leandro Gehlen <leandrogehlen@gmail.com> Co-authored-by: oivanenko <oivanenko@gmail.com> Co-authored-by: AizeLeOuf <florent.coquil@gmail.com>
1 parent 92fec4f commit d8bec71

File tree

20 files changed

+449
-78
lines changed

20 files changed

+449
-78
lines changed

.travis-database.yml

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
test:
2+
adapter: sqlite3
3+
database: db/redmine_test.sqlite3

.travis-init.sh

+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#/bin/bash
2+
3+
if [[ ! "$WORKSPACE" = /* ]] ||
4+
[[ ! "$PATH_TO_PLUGIN" = /* ]] ||
5+
[[ ! "$PATH_TO_REDMINE" = /* ]];
6+
then
7+
echo "You should set"\
8+
" WORKSPACE, PATH_TO_PLUGIN, PATH_TO_REDMINE"\
9+
" environment variables"
10+
echo "You set:"\
11+
"$WORKSPACE"\
12+
"$PATH_TO_PLUGIN"\
13+
"$PATH_TO_REDMINE"
14+
exit 1;
15+
fi
16+
17+
case $REDMINE_VERSION in
18+
1.4.*) export PATH_TO_PLUGINS=./vendor/plugins # for redmine < 2.0
19+
export GENERATE_SECRET=generate_session_store
20+
export MIGRATE_PLUGINS=db:migrate_plugins
21+
export REDMINE_TARBALL=https://github.com/redmine/redmine/archive/$REDMINE_VERSION.tar.gz
22+
;;
23+
2.* | 3.*) export PATH_TO_PLUGINS=./plugins # for redmine 2.x and 3.x
24+
export GENERATE_SECRET=generate_secret_token
25+
export MIGRATE_PLUGINS=redmine:plugins:migrate
26+
export REDMINE_TARBALL=https://github.com/redmine/redmine/archive/$REDMINE_VERSION.tar.gz
27+
;;
28+
master) export PATH_TO_PLUGINS=./plugins
29+
export GENERATE_SECRET=generate_secret_token
30+
export MIGRATE_PLUGINS=redmine:plugins:migrate
31+
export REDMINE_GIT_REPO=https://github.com/redmine/redmine.git
32+
export REDMINE_GIT_TAG=master
33+
;;
34+
*) echo "Unsupported platform $REDMINE_VERSION"
35+
exit 1
36+
;;
37+
esac
38+
39+
export BUNDLE_GEMFILE=$PATH_TO_REDMINE/Gemfile
40+
41+
clone_redmine() {
42+
set -e # exit if clone fails
43+
rm -rf $PATH_TO_REDMINE
44+
if [ ! "$VERBOSE" = "yes" ]; then
45+
QUIET=--quiet
46+
fi
47+
if [ -n "${REDMINE_GIT_TAG}" ]; then
48+
git clone -b $REDMINE_GIT_TAG --depth=100 $QUIET $REDMINE_GIT_REPO $PATH_TO_REDMINE
49+
cd $PATH_TO_REDMINE
50+
git checkout $REDMINE_GIT_TAG
51+
else
52+
mkdir -p $PATH_TO_REDMINE
53+
wget $REDMINE_TARBALL -O- | tar -C $PATH_TO_REDMINE -xz --strip=1 --show-transformed -f -
54+
fi
55+
}
56+
57+
run_tests() {
58+
# exit if tests fail
59+
set -e
60+
61+
cd $PATH_TO_REDMINE
62+
63+
if [ "$VERBOSE" = "yes" ]; then
64+
TRACE=--trace
65+
fi
66+
67+
script -e -c "bundle exec rake redmine:plugins:test NAME="$PLUGIN $VERBOSE
68+
}
69+
70+
uninstall() {
71+
set -e # exit if migrate fails
72+
cd $PATH_TO_REDMINE
73+
# clean up database
74+
if [ "$VERBOSE" = "yes" ]; then
75+
TRACE=--trace
76+
fi
77+
bundle exec rake $TRACE $MIGRATE_PLUGINS NAME=$PLUGIN VERSION=0
78+
}
79+
80+
run_install() {
81+
# exit if install fails
82+
set -e
83+
84+
# cd to redmine folder
85+
cd $PATH_TO_REDMINE
86+
87+
# create a link to the plugin, but avoid recursive link.
88+
if [ -L "$PATH_TO_PLUGINS/$PLUGIN" ]; then rm "$PATH_TO_PLUGINS/$PLUGIN"; fi
89+
ln -s "$PATH_TO_PLUGIN" "$PATH_TO_PLUGINS/$PLUGIN"
90+
91+
if [ "$VERBOSE" = "yes" ]; then
92+
export TRACE=--trace
93+
fi
94+
95+
cp $PATH_TO_PLUGINS/$PLUGIN/.travis-database.yml config/database.yml
96+
97+
# install gems
98+
mkdir -p vendor/bundle
99+
bundle install --path vendor/bundle
100+
101+
bundle exec rake db:migrate $TRACE
102+
bundle exec rake redmine:load_default_data REDMINE_LANG=en $TRACE
103+
bundle exec rake $GENERATE_SECRET $TRACE
104+
bundle exec rake $MIGRATE_PLUGINS $TRACE
105+
}
106+
107+
while getopts :irtu opt
108+
do case "$opt" in
109+
r) clone_redmine; exit 0;;
110+
i) run_install; exit 0;;
111+
t) run_tests $2; exit 0;;
112+
u) uninstall; exit 0;;
113+
[?]) echo "i: install; r: clone redmine; t: run tests; u: uninstall";;
114+
esac
115+
done

.travis.yml

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
language: ruby
22
rvm:
33
- 2.3.3
4-
install: gem install rubocop
4+
branches:
5+
only:
6+
- testing
7+
env:
8+
- REDMINE_VERSION=4.0.6 VERBOSE=yes
59
script:
6-
- rubocop
10+
- export PLUGIN=vault
11+
- export WORKSPACE=$(pwd)/workspace
12+
- export PATH_TO_PLUGIN=$(pwd)
13+
- export PATH_TO_REDMINE=$WORKSPACE/redmine
14+
- mkdir $WORKSPACE
15+
- bash -x ./.travis-init.sh -r || exit 1
16+
- bash -x ./.travis-init.sh -i || exit 1
17+
- bash -x ./.travis-init.sh -t || exit 1
18+
- bash -x ./.travis-init.sh -u || exit 1

app/controllers/keys_controller.rb

+7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class KeysController < ApplicationController
55
before_action :authorize
66
before_action :find_key, only: [ :show, :edit, :update, :destroy, :copy ]
77
before_action :find_keys, only: [ :context_menu ]
8+
accept_api_auth :index, :show
89

910
helper :sort
1011
include SortHelper
@@ -64,6 +65,12 @@ def index
6465
end
6566

6667
@keys.map(&:decrypt!)
68+
69+
respond_to do |format|
70+
format.html
71+
format.pdf
72+
format.json { render json: @keys }
73+
end
6774
end
6875

6976
def new

app/controllers/vault_settings_controller.rb

+10-3
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ def index
1313
end
1414

1515
def save
16+
if params[:settings][:encryption_key].length < 16
17+
redirect_to '/vault_settings', :flash => { :error => t('error.key.length') }
18+
return
19+
end
20+
1621
Setting.send "plugin_vault=", params[:settings]
1722
redirect_to '/vault_settings', notice: t('notice.settings.saved')
1823
end
@@ -43,14 +48,16 @@ def backup
4348

4449
fname = "backup.zip"
4550
temp_file = Tempfile.new(fname)
51+
tmp_fname = temp_file.path
52+
temp_file.close
4653

47-
Zip::File.open(temp_file.path, Zip::File::CREATE) do |zip_file|
54+
Zip::File.open(tmp_fname, Zip::File::CREATE) do |zip_file|
4855
zip_file.file.open('keys.csv', 'w') { |f1| f1 << @csv_string }
4956
zip_file.file.open('tags.csv', 'w') { |f2| f2 << @csv_tag_string }
5057
zip_file.file.open('keys_tags.csv', 'w') { |f3| f3 << @csv_tag_keys_string }
5158
end
5259

53-
zip_data = File.read(temp_file.path)
60+
zip_data = IO.binread(tmp_fname)
5461

5562
send_data zip_data,
5663
:type => 'application/zip',
@@ -96,4 +103,4 @@ def restore
96103
redirect_to '/vault_settings', notice: t('notice.settings.keys_restore')
97104
end
98105

99-
end
106+
end

app/models/vault/key.rb

+42-17
Original file line numberDiff line numberDiff line change
@@ -25,27 +25,52 @@ def self.import(file)
2525
CSV.foreach(file.path, headers:true) do |row|
2626
rhash = row.to_hash
2727

28-
decryptb = Encryptor::decrypt(rhash['body'])
29-
begin
30-
Vault::Key.create(
31-
project_id: rhash['project_id'],
32-
name: rhash['name'],
33-
body: decryptb,
34-
login: rhash['login'],
35-
type: rhash['type'],
36-
file: rhash['file'],
37-
url: rhash['url'],
38-
comment: rhash['comment'],
39-
whitelist: rhash['comment']
40-
).update_column(:id, rhash['id'])
41-
rescue
42-
43-
end
28+
decryptb = Encryptor::decrypt(rhash['body'])
29+
30+
key = Vault::Key.where("name = ?", rhash['name']).first
31+
32+
unless key
33+
begin
34+
Vault::Key.create(
35+
project_id: rhash['project_id'],
36+
name: rhash['name'],
37+
body: decryptb,
38+
login: rhash['login'],
39+
type: rhash['type'],
40+
file: rhash['file'],
41+
url: rhash['url'],
42+
comment: rhash['comment'],
43+
whitelist: rhash['comment']
44+
).update_column(:id, rhash['id'])
45+
rescue
46+
47+
end
48+
else
49+
begin
50+
Vault::Key.update(
51+
key.id,
52+
project_id: rhash['project_id'],
53+
name: rhash['name'],
54+
body: decryptb,
55+
login: rhash['login'],
56+
type: rhash['type'],
57+
file: rhash['file'],
58+
url: rhash['url'],
59+
comment: rhash['comment'],
60+
whitelist: rhash['comment']
61+
)
62+
rescue
63+
64+
end
65+
end
4466
end
4567
end
4668

4769
def whitelisted?(user,project)
4870
return true if user.current.admin or !user.current.allowed_to?(:whitelist_keys, project)
71+
self.whitelist.split(",").each do |id|
72+
return true if User.in_group(id).where(:id => user.current.id).count == 1
73+
end
4974
return self.whitelist.split(",").include?(user.current.id.to_s)
5075
end
5176

@@ -54,4 +79,4 @@ def whitelisted?(user,project)
5479
class Vault::KeysVaultTags < ActiveRecord::Base
5580
end
5681

57-
end
82+
end

app/views/keys/_form.html.erb

+3-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,9 @@
5050

5151
<% if User.current.allowed_to?(:manage_whitelist_keys, @project) %>
5252
<% whitelisted = @key.whitelist.split(",") %>
53-
<% all_users = @project.memberships.active.where(:users => {:type => 'User'}).sort.map {|u| [u.principal, u.principal.id.to_s]} %>
53+
<% all_users = @project.memberships.active.where(:users => {:type => 'User'}).sort.map {|u| [u.principal, u.principal.id.to_s]} %>
54+
<% all_groups = @project.memberships.active.where(:users => {:type => 'Group'}).sort.map {|u| [u.principal, u.principal.id.to_s]} %>
55+
<% all_users = all_groups|all_users %>
5456
<div id="vault_whitelist">
5557
<%= f.label t('key.attr.whitelist') ,class: "whitelist_users"%>
5658

app/views/keys/index.html.erb

+1-3
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22
<%= stylesheet_link_tag "font-awesome.css", :plugin => "vault" %>
33
<%= stylesheet_link_tag "font-awesome.min.css", :plugin => "vault" %>
44
<%= javascript_include_tag 'vault', :plugin => 'vault' %>
5-
6-
7-
<% end %>
5+
<% end %>
86

97
<div class="contextual">
108
<%= link_to t('key.btn.new'), new_project_key_path(@project), class: 'icon icon-add' if User.current.allowed_to?(:view_keys, @project) if User.current.allowed_to?(:edit_keys, @project) %>

app/views/keys/show.html.erb

+6
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
<% content_for :header_tags do %>
2+
<%= stylesheet_link_tag "font-awesome.css", :plugin => "vault" %>
3+
<%= stylesheet_link_tag "font-awesome.min.css", :plugin => "vault" %>
4+
<%= javascript_include_tag 'vault', :plugin => 'vault' %>
5+
<% end %>
6+
17
<h1> <%= t('key.title.show') %> </h1>
28

39
<%= render @key %>

app/views/vault_settings/index.html.erb

-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
<%= stylesheet_link_tag "font-awesome.css", :plugin => "vault" %>
55
<%= stylesheet_link_tag "font-awesome.min.css", :plugin => "vault" %>
66
<%= javascript_include_tag 'vault', :plugin => 'vault' %>
7-
8-
97
<% end %>
108

119
<div id="settings">

assets/images/locked.png

1013 Bytes
Loading

assets/javascripts/vault.js

+23-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,33 @@
11
$(function () {
2-
2+
33
function copyToClipboard( elementId ) {
4-
var $temp = $( "<input>" ).val( $( "#" + elementId ).text() );
5-
$( "body" ).append($temp);
6-
$temp.select();
7-
document.execCommand("copy");
8-
$temp.remove();
4+
var $temp = $( "<input>" ).val( $( "#" + elementId ).text() );
5+
$( "body" ).append($temp);
6+
$temp.select();
7+
document.execCommand("copy");
8+
$temp.remove();
99
}
1010

1111
$("a.copy-key").click(function () {
12-
copyToClipboard($(this).data('clipboard-target'));
12+
copyToClipboard($(this).data('clipboard-target'));
1313
});
1414

1515
// toggle label display between actual passwords and *****
16-
$('td.key-password-column label').click(function () {
16+
/*$('td.key-password-column label').click(function () {
1717
$(this).parents("td:first").find('label').toggle();
18-
});
18+
});*/
19+
$('label[id*="plain_pass"]').click(function () {
20+
exchangePassword($(this));
21+
});
22+
23+
$('label[id*="plain_pass"]').each(function(){
24+
$(this).prev().click(function(){
25+
exchangePassword($(this).next());
26+
});
27+
});
28+
29+
function exchangePassword(hiddenLabel){
30+
hiddenLabel.toggle();
31+
hiddenLabel.prev().toggle();
32+
}
1933
});

assets/stylesheets/vault.css

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22

33
#keys_table a.keys-actions:hover, a.keys-actions:active { color: #c61a1a; text-decoration: none; cursor: pointer; font-size: 120%; }
44
#tags-list { -webkit-column-count: 3; -moz-column-count: 3; column-count: 3; }
5-
#admin-menu a.vault { background-image: url("/images/locked.png"); }
5+
6+
.vault { background-image: url("../images/locked.png"); }
67

78
#vault_context_menu li.conext_menu { color: #888; text-decoration: none; font-size: 100%; padding: 0; cursor: pointer; }
89
#vault_context_menu a.conext_menu { color: #888; text-decoration: none; font-size: 100%; padding: 0; }

config/locales/en.yml

+2-1
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,5 @@ en:
8989
error:
9090
key:
9191
not_set: "The encryption key is not set in the settings"
92-
not_whitelisted: "Key not allowed for you"
92+
not_whitelisted: "Key not allowed for you"
93+
length: "Encryption key must be at least 16 symbols"

0 commit comments

Comments
 (0)