gist 4.6.0 → 4.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -3
- data/build/gist +2 -293
- data/lib/gist.rb +2 -8
- metadata +2 -3
- data/vendor/netrc.rb +0 -286
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2f19484015dcf7461d0498fa37013e616aec23b4
|
4
|
+
data.tar.gz: e8784bc46d7261281acb0c947c8670c01588399a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3307a3891b8fc1d302ba15092ca165ec72dbeb773c0ca4f47a6a079716747864b475410192fd8a5f8afcff06e78378c414a1d39641c8421e2dd4d1c244a4faba
|
7
|
+
data.tar.gz: 865d65b608b91d4c258215e6d4e8b6af6278d2e78c0d368d66dcee146e69fd0fd293fe63f7031f273c177d259ac1cc3d5e713684b13dd1632d84a7442cede8b2
|
data/Rakefile
CHANGED
@@ -23,9 +23,7 @@ task :standalone do
|
|
23
23
|
f.puts "#!/usr/bin/env ruby"
|
24
24
|
f.puts "# This is generated from https://github.com/defunkt/gist using 'rake standalone'"
|
25
25
|
f.puts "# any changes will be overwritten."
|
26
|
-
f.puts File.read("lib/gist.rb")
|
27
|
-
.split("require 'json'\n").join(File.read("vendor/json.rb"))
|
28
|
-
.split("require 'netrc'\n").join(File.read("vendor/netrc.rb"))
|
26
|
+
f.puts File.read("lib/gist.rb").split("require 'json'\n").join(File.read("vendor/json.rb"))
|
29
27
|
|
30
28
|
f.puts File.read("bin/gist").gsub(/^require.*gist.*\n/, '');
|
31
29
|
end
|
data/build/gist
CHANGED
@@ -1314,302 +1314,11 @@ rescue LoadError
|
|
1314
1314
|
require File.join File.dirname(File.dirname(__FILE__)), 'vendor', 'json.rb'
|
1315
1315
|
end
|
1316
1316
|
|
1317
|
-
begin
|
1318
|
-
|
1319
|
-
# The netrc library (https://github.com/heroku/netrc) is reproduced below, along
|
1320
|
-
# with its copyright and license:
|
1321
|
-
# - https://raw.githubusercontent.com/heroku/netrc/262ef111/LICENSE.md
|
1322
|
-
# - https://raw.githubusercontent.com/heroku/netrc/262ef111/lib/netrc.rb
|
1323
|
-
|
1324
|
-
# The MIT License (MIT)
|
1325
|
-
#
|
1326
|
-
# Copyright (c) 2011-2014 [CONTRIBUTORS.md](https://github.com/geemus/netrc/blob/master/CONTRIBUTORS.md)
|
1327
|
-
#
|
1328
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
1329
|
-
# this software and associated documentation files (the "Software"), to deal in
|
1330
|
-
# the Software without restriction, including without limitation the rights to
|
1331
|
-
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
1332
|
-
# the Software, and to permit persons to whom the Software is furnished to do so,
|
1333
|
-
# subject to the following conditions:
|
1334
|
-
#
|
1335
|
-
# The above copyright notice and this permission notice shall be included in all
|
1336
|
-
# copies or substantial portions of the Software.
|
1337
|
-
#
|
1338
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
1339
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
1340
|
-
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
1341
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
1342
|
-
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
1343
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
1344
|
-
|
1345
|
-
require 'rbconfig'
|
1346
|
-
require 'io/console'
|
1347
|
-
|
1348
|
-
class Netrc
|
1349
|
-
VERSION = "0.11.0"
|
1350
|
-
|
1351
|
-
# see http://stackoverflow.com/questions/4871309/what-is-the-correct-way-to-detect-if-ruby-is-running-on-windows
|
1352
|
-
WINDOWS = RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
|
1353
|
-
CYGWIN = RbConfig::CONFIG["host_os"] =~ /cygwin/
|
1354
|
-
|
1355
|
-
def self.default_path
|
1356
|
-
File.join(ENV['NETRC'] || home_path, netrc_filename)
|
1357
|
-
end
|
1358
|
-
|
1359
|
-
def self.home_path
|
1360
|
-
home = Dir.respond_to?(:home) ? Dir.home : ENV['HOME']
|
1361
|
-
|
1362
|
-
if WINDOWS && !CYGWIN
|
1363
|
-
home ||= File.join(ENV['HOMEDRIVE'], ENV['HOMEPATH']) if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
|
1364
|
-
home ||= ENV['USERPROFILE']
|
1365
|
-
# XXX: old stuff; most likely unnecessary
|
1366
|
-
home = home.tr("\\", "/") unless home.nil?
|
1367
|
-
end
|
1368
|
-
|
1369
|
-
(home && File.readable?(home)) ? home : Dir.pwd
|
1370
|
-
rescue ArgumentError
|
1371
|
-
return Dir.pwd
|
1372
|
-
end
|
1373
|
-
|
1374
|
-
def self.netrc_filename
|
1375
|
-
WINDOWS && !CYGWIN ? "_netrc" : ".netrc"
|
1376
|
-
end
|
1377
|
-
|
1378
|
-
def self.config
|
1379
|
-
@config ||= {}
|
1380
|
-
end
|
1381
|
-
|
1382
|
-
def self.configure
|
1383
|
-
yield(self.config) if block_given?
|
1384
|
-
self.config
|
1385
|
-
end
|
1386
|
-
|
1387
|
-
def self.check_permissions(path)
|
1388
|
-
perm = File.stat(path).mode & 0777
|
1389
|
-
if perm != 0600 && !(WINDOWS) && !(Netrc.config[:allow_permissive_netrc_file])
|
1390
|
-
raise Error, "Permission bits for '#{path}' should be 0600, but are "+perm.to_s(8)
|
1391
|
-
end
|
1392
|
-
end
|
1393
|
-
|
1394
|
-
# Reads path and parses it as a .netrc file. If path doesn't
|
1395
|
-
# exist, returns an empty object. Decrypt paths ending in .gpg.
|
1396
|
-
def self.read(path=default_path)
|
1397
|
-
check_permissions(path)
|
1398
|
-
data = if path =~ /\.gpg$/
|
1399
|
-
decrypted = if ENV['GPG_AGENT_INFO']
|
1400
|
-
`gpg --batch --quiet --decrypt #{path}`
|
1401
|
-
else
|
1402
|
-
print "Enter passphrase for #{path}: "
|
1403
|
-
STDIN.noecho do
|
1404
|
-
`gpg --batch --passphrase-fd 0 --quiet --decrypt #{path}`
|
1405
|
-
end
|
1406
|
-
end
|
1407
|
-
if $?.success?
|
1408
|
-
decrypted
|
1409
|
-
else
|
1410
|
-
raise Error.new("Decrypting #{path} failed.") unless $?.success?
|
1411
|
-
end
|
1412
|
-
else
|
1413
|
-
File.read(path)
|
1414
|
-
end
|
1415
|
-
new(path, parse(lex(data.lines.to_a)))
|
1416
|
-
rescue Errno::ENOENT
|
1417
|
-
new(path, parse(lex([])))
|
1418
|
-
end
|
1419
|
-
|
1420
|
-
class TokenArray < Array
|
1421
|
-
def take
|
1422
|
-
if length < 1
|
1423
|
-
raise Error, "unexpected EOF"
|
1424
|
-
end
|
1425
|
-
shift
|
1426
|
-
end
|
1427
|
-
|
1428
|
-
def readto
|
1429
|
-
l = []
|
1430
|
-
while length > 0 && ! yield(self[0])
|
1431
|
-
l << shift
|
1432
|
-
end
|
1433
|
-
return l.join
|
1434
|
-
end
|
1435
|
-
end
|
1436
|
-
|
1437
|
-
def self.lex(lines)
|
1438
|
-
tokens = TokenArray.new
|
1439
|
-
for line in lines
|
1440
|
-
content, comment = line.split(/(\s*#.*)/m)
|
1441
|
-
content.each_char do |char|
|
1442
|
-
case char
|
1443
|
-
when /\s/
|
1444
|
-
if tokens.last && tokens.last[-1..-1] =~ /\s/
|
1445
|
-
tokens.last << char
|
1446
|
-
else
|
1447
|
-
tokens << char
|
1448
|
-
end
|
1449
|
-
else
|
1450
|
-
if tokens.last && tokens.last[-1..-1] =~ /\S/
|
1451
|
-
tokens.last << char
|
1452
|
-
else
|
1453
|
-
tokens << char
|
1454
|
-
end
|
1455
|
-
end
|
1456
|
-
end
|
1457
|
-
if comment
|
1458
|
-
tokens << comment
|
1459
|
-
end
|
1460
|
-
end
|
1461
|
-
tokens
|
1462
|
-
end
|
1463
|
-
|
1464
|
-
def self.skip?(s)
|
1465
|
-
s =~ /^\s/
|
1466
|
-
end
|
1467
|
-
|
1468
|
-
|
1469
|
-
|
1470
|
-
# Returns two values, a header and a list of items.
|
1471
|
-
# Each item is a tuple, containing some or all of:
|
1472
|
-
# - machine keyword (including trailing whitespace+comments)
|
1473
|
-
# - machine name
|
1474
|
-
# - login keyword (including surrounding whitespace+comments)
|
1475
|
-
# - login
|
1476
|
-
# - password keyword (including surrounding whitespace+comments)
|
1477
|
-
# - password
|
1478
|
-
# - trailing chars
|
1479
|
-
# This lets us change individual fields, then write out the file
|
1480
|
-
# with all its original formatting.
|
1481
|
-
def self.parse(ts)
|
1482
|
-
cur, item = [], []
|
1483
|
-
|
1484
|
-
unless ts.is_a?(TokenArray)
|
1485
|
-
ts = TokenArray.new(ts)
|
1486
|
-
end
|
1487
|
-
|
1488
|
-
pre = ts.readto{|t| t == "machine" || t == "default"}
|
1489
|
-
|
1490
|
-
while ts.length > 0
|
1491
|
-
if ts[0] == 'default'
|
1492
|
-
cur << ts.take.to_sym
|
1493
|
-
cur << ''
|
1494
|
-
else
|
1495
|
-
cur << ts.take + ts.readto{|t| ! skip?(t)}
|
1496
|
-
cur << ts.take
|
1497
|
-
end
|
1498
|
-
|
1499
|
-
if ts.include?('login')
|
1500
|
-
cur << ts.readto{|t| t == "login"} + ts.take + ts.readto{|t| ! skip?(t)}
|
1501
|
-
cur << ts.take
|
1502
|
-
end
|
1503
|
-
|
1504
|
-
if ts.include?('password')
|
1505
|
-
cur << ts.readto{|t| t == "password"} + ts.take + ts.readto{|t| ! skip?(t)}
|
1506
|
-
cur << ts.take
|
1507
|
-
end
|
1508
|
-
|
1509
|
-
cur << ts.readto{|t| t == "machine" || t == "default"}
|
1510
|
-
|
1511
|
-
item << cur
|
1512
|
-
cur = []
|
1513
|
-
end
|
1514
|
-
|
1515
|
-
[pre, item]
|
1516
|
-
end
|
1517
|
-
|
1518
|
-
def initialize(path, data)
|
1519
|
-
@new_item_prefix = ''
|
1520
|
-
@path = path
|
1521
|
-
@pre, @data = data
|
1522
|
-
|
1523
|
-
if @data && @data.last && :default == @data.last[0]
|
1524
|
-
@default = @data.pop
|
1525
|
-
else
|
1526
|
-
@default = nil
|
1527
|
-
end
|
1528
|
-
end
|
1529
|
-
|
1530
|
-
attr_accessor :new_item_prefix
|
1531
|
-
|
1532
|
-
def [](k)
|
1533
|
-
if item = @data.detect {|datum| datum[1] == k}
|
1534
|
-
Entry.new(item[3], item[5])
|
1535
|
-
elsif @default
|
1536
|
-
Entry.new(@default[3], @default[5])
|
1537
|
-
end
|
1538
|
-
end
|
1539
|
-
|
1540
|
-
def []=(k, info)
|
1541
|
-
if item = @data.detect {|datum| datum[1] == k}
|
1542
|
-
item[3], item[5] = info
|
1543
|
-
else
|
1544
|
-
@data << new_item(k, info[0], info[1])
|
1545
|
-
end
|
1546
|
-
end
|
1547
|
-
|
1548
|
-
def length
|
1549
|
-
@data.length
|
1550
|
-
end
|
1551
|
-
|
1552
|
-
def delete(key)
|
1553
|
-
datum = nil
|
1554
|
-
for value in @data
|
1555
|
-
if value[1] == key
|
1556
|
-
datum = value
|
1557
|
-
break
|
1558
|
-
end
|
1559
|
-
end
|
1560
|
-
@data.delete(datum)
|
1561
|
-
end
|
1562
|
-
|
1563
|
-
def each(&block)
|
1564
|
-
@data.each(&block)
|
1565
|
-
end
|
1566
|
-
|
1567
|
-
def new_item(m, l, p)
|
1568
|
-
[new_item_prefix+"machine ", m, "\n login ", l, "\n password ", p, "\n"]
|
1569
|
-
end
|
1570
|
-
|
1571
|
-
def save
|
1572
|
-
if @path =~ /\.gpg$/
|
1573
|
-
e = IO.popen("gpg -a --batch --default-recipient-self -e", "r+") do |gpg|
|
1574
|
-
gpg.puts(unparse)
|
1575
|
-
gpg.close_write
|
1576
|
-
gpg.read
|
1577
|
-
end
|
1578
|
-
raise Error.new("Encrypting #{@path} failed.") unless $?.success?
|
1579
|
-
File.open(@path, 'w', 0600) {|file| file.print(e)}
|
1580
|
-
else
|
1581
|
-
File.open(@path, 'w', 0600) {|file| file.print(unparse)}
|
1582
|
-
end
|
1583
|
-
end
|
1584
|
-
|
1585
|
-
def unparse
|
1586
|
-
@pre + @data.map do |datum|
|
1587
|
-
datum = datum.join
|
1588
|
-
unless datum[-1..-1] == "\n"
|
1589
|
-
datum << "\n"
|
1590
|
-
else
|
1591
|
-
datum
|
1592
|
-
end
|
1593
|
-
end.join
|
1594
|
-
end
|
1595
|
-
|
1596
|
-
Entry = Struct.new(:login, :password) do
|
1597
|
-
alias to_ary to_a
|
1598
|
-
end
|
1599
|
-
|
1600
|
-
end
|
1601
|
-
|
1602
|
-
class Netrc::Error < ::StandardError
|
1603
|
-
end
|
1604
|
-
rescue LoadError
|
1605
|
-
require File.join File.dirname(File.dirname(__FILE__)), 'vendor', 'netrc.rb'
|
1606
|
-
end
|
1607
|
-
|
1608
1317
|
# It just gists.
|
1609
1318
|
module Gist
|
1610
1319
|
extend self
|
1611
1320
|
|
1612
|
-
VERSION = '4.6.
|
1321
|
+
VERSION = '4.6.1'
|
1613
1322
|
|
1614
1323
|
# A list of clipboard commands with copy and paste support.
|
1615
1324
|
CLIPBOARD_COMMANDS = {
|
@@ -1662,7 +1371,7 @@ module Gist
|
|
1662
1371
|
#
|
1663
1372
|
# @return [String] string value of access token or `nil`, if not found
|
1664
1373
|
def auth_token
|
1665
|
-
@token ||= AuthTokenFile.read rescue nil
|
1374
|
+
@token ||= AuthTokenFile.read rescue nil
|
1666
1375
|
end
|
1667
1376
|
|
1668
1377
|
# Upload a gist to https://gist.github.com
|
data/lib/gist.rb
CHANGED
@@ -8,17 +8,11 @@ rescue LoadError
|
|
8
8
|
require File.join File.dirname(File.dirname(__FILE__)), 'vendor', 'json.rb'
|
9
9
|
end
|
10
10
|
|
11
|
-
begin
|
12
|
-
require 'netrc'
|
13
|
-
rescue LoadError
|
14
|
-
require File.join File.dirname(File.dirname(__FILE__)), 'vendor', 'netrc.rb'
|
15
|
-
end
|
16
|
-
|
17
11
|
# It just gists.
|
18
12
|
module Gist
|
19
13
|
extend self
|
20
14
|
|
21
|
-
VERSION = '4.6.
|
15
|
+
VERSION = '4.6.1'
|
22
16
|
|
23
17
|
# A list of clipboard commands with copy and paste support.
|
24
18
|
CLIPBOARD_COMMANDS = {
|
@@ -71,7 +65,7 @@ module Gist
|
|
71
65
|
#
|
72
66
|
# @return [String] string value of access token or `nil`, if not found
|
73
67
|
def auth_token
|
74
|
-
@token ||= AuthTokenFile.read rescue nil
|
68
|
+
@token ||= AuthTokenFile.read rescue nil
|
75
69
|
end
|
76
70
|
|
77
71
|
# Upload a gist to https://gist.github.com
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gist
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.6.
|
4
|
+
version: 4.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Conrad Irwin
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-05-
|
12
|
+
date: 2017-05-17 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -96,7 +96,6 @@ files:
|
|
96
96
|
- spec/shorten_spec.rb
|
97
97
|
- spec/spec_helper.rb
|
98
98
|
- vendor/json.rb
|
99
|
-
- vendor/netrc.rb
|
100
99
|
homepage: https://github.com/defunkt/gist
|
101
100
|
licenses:
|
102
101
|
- MIT
|
data/vendor/netrc.rb
DELETED
@@ -1,286 +0,0 @@
|
|
1
|
-
|
2
|
-
# The netrc library (https://github.com/heroku/netrc) is reproduced below, along
|
3
|
-
# with its copyright and license:
|
4
|
-
# - https://raw.githubusercontent.com/heroku/netrc/262ef111/LICENSE.md
|
5
|
-
# - https://raw.githubusercontent.com/heroku/netrc/262ef111/lib/netrc.rb
|
6
|
-
|
7
|
-
# The MIT License (MIT)
|
8
|
-
#
|
9
|
-
# Copyright (c) 2011-2014 [CONTRIBUTORS.md](https://github.com/geemus/netrc/blob/master/CONTRIBUTORS.md)
|
10
|
-
#
|
11
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy of
|
12
|
-
# this software and associated documentation files (the "Software"), to deal in
|
13
|
-
# the Software without restriction, including without limitation the rights to
|
14
|
-
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
15
|
-
# the Software, and to permit persons to whom the Software is furnished to do so,
|
16
|
-
# subject to the following conditions:
|
17
|
-
#
|
18
|
-
# The above copyright notice and this permission notice shall be included in all
|
19
|
-
# copies or substantial portions of the Software.
|
20
|
-
#
|
21
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
22
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
23
|
-
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
24
|
-
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
25
|
-
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
26
|
-
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27
|
-
|
28
|
-
require 'rbconfig'
|
29
|
-
require 'io/console'
|
30
|
-
|
31
|
-
class Netrc
|
32
|
-
VERSION = "0.11.0"
|
33
|
-
|
34
|
-
# see http://stackoverflow.com/questions/4871309/what-is-the-correct-way-to-detect-if-ruby-is-running-on-windows
|
35
|
-
WINDOWS = RbConfig::CONFIG["host_os"] =~ /mswin|mingw|cygwin/
|
36
|
-
CYGWIN = RbConfig::CONFIG["host_os"] =~ /cygwin/
|
37
|
-
|
38
|
-
def self.default_path
|
39
|
-
File.join(ENV['NETRC'] || home_path, netrc_filename)
|
40
|
-
end
|
41
|
-
|
42
|
-
def self.home_path
|
43
|
-
home = Dir.respond_to?(:home) ? Dir.home : ENV['HOME']
|
44
|
-
|
45
|
-
if WINDOWS && !CYGWIN
|
46
|
-
home ||= File.join(ENV['HOMEDRIVE'], ENV['HOMEPATH']) if ENV['HOMEDRIVE'] && ENV['HOMEPATH']
|
47
|
-
home ||= ENV['USERPROFILE']
|
48
|
-
# XXX: old stuff; most likely unnecessary
|
49
|
-
home = home.tr("\\", "/") unless home.nil?
|
50
|
-
end
|
51
|
-
|
52
|
-
(home && File.readable?(home)) ? home : Dir.pwd
|
53
|
-
rescue ArgumentError
|
54
|
-
return Dir.pwd
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.netrc_filename
|
58
|
-
WINDOWS && !CYGWIN ? "_netrc" : ".netrc"
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.config
|
62
|
-
@config ||= {}
|
63
|
-
end
|
64
|
-
|
65
|
-
def self.configure
|
66
|
-
yield(self.config) if block_given?
|
67
|
-
self.config
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.check_permissions(path)
|
71
|
-
perm = File.stat(path).mode & 0777
|
72
|
-
if perm != 0600 && !(WINDOWS) && !(Netrc.config[:allow_permissive_netrc_file])
|
73
|
-
raise Error, "Permission bits for '#{path}' should be 0600, but are "+perm.to_s(8)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Reads path and parses it as a .netrc file. If path doesn't
|
78
|
-
# exist, returns an empty object. Decrypt paths ending in .gpg.
|
79
|
-
def self.read(path=default_path)
|
80
|
-
check_permissions(path)
|
81
|
-
data = if path =~ /\.gpg$/
|
82
|
-
decrypted = if ENV['GPG_AGENT_INFO']
|
83
|
-
`gpg --batch --quiet --decrypt #{path}`
|
84
|
-
else
|
85
|
-
print "Enter passphrase for #{path}: "
|
86
|
-
STDIN.noecho do
|
87
|
-
`gpg --batch --passphrase-fd 0 --quiet --decrypt #{path}`
|
88
|
-
end
|
89
|
-
end
|
90
|
-
if $?.success?
|
91
|
-
decrypted
|
92
|
-
else
|
93
|
-
raise Error.new("Decrypting #{path} failed.") unless $?.success?
|
94
|
-
end
|
95
|
-
else
|
96
|
-
File.read(path)
|
97
|
-
end
|
98
|
-
new(path, parse(lex(data.lines.to_a)))
|
99
|
-
rescue Errno::ENOENT
|
100
|
-
new(path, parse(lex([])))
|
101
|
-
end
|
102
|
-
|
103
|
-
class TokenArray < Array
|
104
|
-
def take
|
105
|
-
if length < 1
|
106
|
-
raise Error, "unexpected EOF"
|
107
|
-
end
|
108
|
-
shift
|
109
|
-
end
|
110
|
-
|
111
|
-
def readto
|
112
|
-
l = []
|
113
|
-
while length > 0 && ! yield(self[0])
|
114
|
-
l << shift
|
115
|
-
end
|
116
|
-
return l.join
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def self.lex(lines)
|
121
|
-
tokens = TokenArray.new
|
122
|
-
for line in lines
|
123
|
-
content, comment = line.split(/(\s*#.*)/m)
|
124
|
-
content.each_char do |char|
|
125
|
-
case char
|
126
|
-
when /\s/
|
127
|
-
if tokens.last && tokens.last[-1..-1] =~ /\s/
|
128
|
-
tokens.last << char
|
129
|
-
else
|
130
|
-
tokens << char
|
131
|
-
end
|
132
|
-
else
|
133
|
-
if tokens.last && tokens.last[-1..-1] =~ /\S/
|
134
|
-
tokens.last << char
|
135
|
-
else
|
136
|
-
tokens << char
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
if comment
|
141
|
-
tokens << comment
|
142
|
-
end
|
143
|
-
end
|
144
|
-
tokens
|
145
|
-
end
|
146
|
-
|
147
|
-
def self.skip?(s)
|
148
|
-
s =~ /^\s/
|
149
|
-
end
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
# Returns two values, a header and a list of items.
|
154
|
-
# Each item is a tuple, containing some or all of:
|
155
|
-
# - machine keyword (including trailing whitespace+comments)
|
156
|
-
# - machine name
|
157
|
-
# - login keyword (including surrounding whitespace+comments)
|
158
|
-
# - login
|
159
|
-
# - password keyword (including surrounding whitespace+comments)
|
160
|
-
# - password
|
161
|
-
# - trailing chars
|
162
|
-
# This lets us change individual fields, then write out the file
|
163
|
-
# with all its original formatting.
|
164
|
-
def self.parse(ts)
|
165
|
-
cur, item = [], []
|
166
|
-
|
167
|
-
unless ts.is_a?(TokenArray)
|
168
|
-
ts = TokenArray.new(ts)
|
169
|
-
end
|
170
|
-
|
171
|
-
pre = ts.readto{|t| t == "machine" || t == "default"}
|
172
|
-
|
173
|
-
while ts.length > 0
|
174
|
-
if ts[0] == 'default'
|
175
|
-
cur << ts.take.to_sym
|
176
|
-
cur << ''
|
177
|
-
else
|
178
|
-
cur << ts.take + ts.readto{|t| ! skip?(t)}
|
179
|
-
cur << ts.take
|
180
|
-
end
|
181
|
-
|
182
|
-
if ts.include?('login')
|
183
|
-
cur << ts.readto{|t| t == "login"} + ts.take + ts.readto{|t| ! skip?(t)}
|
184
|
-
cur << ts.take
|
185
|
-
end
|
186
|
-
|
187
|
-
if ts.include?('password')
|
188
|
-
cur << ts.readto{|t| t == "password"} + ts.take + ts.readto{|t| ! skip?(t)}
|
189
|
-
cur << ts.take
|
190
|
-
end
|
191
|
-
|
192
|
-
cur << ts.readto{|t| t == "machine" || t == "default"}
|
193
|
-
|
194
|
-
item << cur
|
195
|
-
cur = []
|
196
|
-
end
|
197
|
-
|
198
|
-
[pre, item]
|
199
|
-
end
|
200
|
-
|
201
|
-
def initialize(path, data)
|
202
|
-
@new_item_prefix = ''
|
203
|
-
@path = path
|
204
|
-
@pre, @data = data
|
205
|
-
|
206
|
-
if @data && @data.last && :default == @data.last[0]
|
207
|
-
@default = @data.pop
|
208
|
-
else
|
209
|
-
@default = nil
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
attr_accessor :new_item_prefix
|
214
|
-
|
215
|
-
def [](k)
|
216
|
-
if item = @data.detect {|datum| datum[1] == k}
|
217
|
-
Entry.new(item[3], item[5])
|
218
|
-
elsif @default
|
219
|
-
Entry.new(@default[3], @default[5])
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
def []=(k, info)
|
224
|
-
if item = @data.detect {|datum| datum[1] == k}
|
225
|
-
item[3], item[5] = info
|
226
|
-
else
|
227
|
-
@data << new_item(k, info[0], info[1])
|
228
|
-
end
|
229
|
-
end
|
230
|
-
|
231
|
-
def length
|
232
|
-
@data.length
|
233
|
-
end
|
234
|
-
|
235
|
-
def delete(key)
|
236
|
-
datum = nil
|
237
|
-
for value in @data
|
238
|
-
if value[1] == key
|
239
|
-
datum = value
|
240
|
-
break
|
241
|
-
end
|
242
|
-
end
|
243
|
-
@data.delete(datum)
|
244
|
-
end
|
245
|
-
|
246
|
-
def each(&block)
|
247
|
-
@data.each(&block)
|
248
|
-
end
|
249
|
-
|
250
|
-
def new_item(m, l, p)
|
251
|
-
[new_item_prefix+"machine ", m, "\n login ", l, "\n password ", p, "\n"]
|
252
|
-
end
|
253
|
-
|
254
|
-
def save
|
255
|
-
if @path =~ /\.gpg$/
|
256
|
-
e = IO.popen("gpg -a --batch --default-recipient-self -e", "r+") do |gpg|
|
257
|
-
gpg.puts(unparse)
|
258
|
-
gpg.close_write
|
259
|
-
gpg.read
|
260
|
-
end
|
261
|
-
raise Error.new("Encrypting #{@path} failed.") unless $?.success?
|
262
|
-
File.open(@path, 'w', 0600) {|file| file.print(e)}
|
263
|
-
else
|
264
|
-
File.open(@path, 'w', 0600) {|file| file.print(unparse)}
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
def unparse
|
269
|
-
@pre + @data.map do |datum|
|
270
|
-
datum = datum.join
|
271
|
-
unless datum[-1..-1] == "\n"
|
272
|
-
datum << "\n"
|
273
|
-
else
|
274
|
-
datum
|
275
|
-
end
|
276
|
-
end.join
|
277
|
-
end
|
278
|
-
|
279
|
-
Entry = Struct.new(:login, :password) do
|
280
|
-
alias to_ary to_a
|
281
|
-
end
|
282
|
-
|
283
|
-
end
|
284
|
-
|
285
|
-
class Netrc::Error < ::StandardError
|
286
|
-
end
|