gist 4.6.0 → 4.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|