iated 0.0.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.
Files changed (54) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +3 -0
  3. data/Guardfile +24 -0
  4. data/LICENSE +23 -0
  5. data/Makefile +72 -0
  6. data/README.md +87 -0
  7. data/Rakefile +10 -0
  8. data/bin/iated +13 -0
  9. data/config.ru +5 -0
  10. data/extensions/chrome/background.html +5 -0
  11. data/extensions/chrome/background.js +105 -0
  12. data/extensions/chrome/contentscript.css +0 -0
  13. data/extensions/chrome/contentscript.js +110 -0
  14. data/extensions/chrome/jquery-ui.js +45 -0
  15. data/extensions/chrome/jquery.js +16 -0
  16. data/extensions/chrome/jquery.updater.js +46 -0
  17. data/extensions/chrome/manifest.json +19 -0
  18. data/extensions/chrome/yaml.js +489 -0
  19. data/extensions/tests/simple.html +23 -0
  20. data/features/extension_authenticates.feature +30 -0
  21. data/features/extension_edits.feature +45 -0
  22. data/features/step_definitions/extension_steps.rb +134 -0
  23. data/features/support/env.rb +47 -0
  24. data/features/support/hooks.rb +11 -0
  25. data/iated.gemspec +48 -0
  26. data/lib/iated.rb +111 -0
  27. data/lib/iated/browser_token_db.rb +76 -0
  28. data/lib/iated/edit_session.rb +221 -0
  29. data/lib/iated/helpers.rb +9 -0
  30. data/lib/iated/mcp.rb +144 -0
  31. data/lib/iated/page_helpers.rb +33 -0
  32. data/lib/iated/public/jquery-ui.js +101 -0
  33. data/lib/iated/public/jquery.js +2 -0
  34. data/lib/iated/public/robots.txt +5 -0
  35. data/lib/iated/server.rb +162 -0
  36. data/lib/iated/sys_pref.rb +201 -0
  37. data/lib/iated/version.rb +3 -0
  38. data/lib/iated/views/hello.haml +13 -0
  39. data/lib/iated/views/preferences.haml +27 -0
  40. data/lib/iated/views/reference.coffee +79 -0
  41. data/lib/iated/views/reference.haml +94 -0
  42. data/lib/iated/views/reference.scss +36 -0
  43. data/lib/iated/views/root.haml +13 -0
  44. data/spec/lib/iated/browser_token_db_spec.rb +68 -0
  45. data/spec/lib/iated/edit_session_spec.rb +157 -0
  46. data/spec/lib/iated/mcp_spec.rb +86 -0
  47. data/spec/lib/iated/sys_pref_spec.rb +40 -0
  48. data/spec/protocol/edit_spec.rb +88 -0
  49. data/spec/protocol/hello_spec.rb +18 -0
  50. data/spec/protocol/notfound_spec.rb +11 -0
  51. data/spec/protocol/ping_spec.rb +10 -0
  52. data/spec/protocol/preferences_spec.rb +35 -0
  53. data/spec/spec_helper.rb +21 -0
  54. metadata +460 -0
@@ -0,0 +1,3 @@
1
+ module Iated
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,13 @@
1
+ !!!
2
+ %meta( charset="utf-8" )
3
+ %title Authorize Iated
4
+
5
+ %body( id="hello" )
6
+ %h1 Authorize Iated
7
+
8
+ %form( method="post" )
9
+ %input( type="text" name="onetime" )
10
+ %input( type="submit" name="Authorize!" )
11
+
12
+ %pre
13
+ %= params.inspect
@@ -0,0 +1,27 @@
1
+ !!!
2
+ %meta( charset="utf-8" )
3
+ %title It's All Text!
4
+ %link( rel="stylesheet" type="text/css" href="iated.css" )
5
+
6
+ %body( class="preferences" )
7
+
8
+ %div( id="content" )
9
+ %h1
10
+ It's All Text! Preferences
11
+
12
+ %form( method="post" action="/preferences" )
13
+ %input( type="hidden" name="token" value="#{token}" )
14
+
15
+ %label( for="editor" )
16
+ Editor:
17
+ %input( type="text" name="editor" value="#{editor}")
18
+
19
+ %label( for="port" )
20
+ Port:
21
+ %input( type="text" name="port" value="#{port}")
22
+
23
+ %label( for="config_dir" )
24
+ Config Directory:
25
+ %input( type="text" name="config_dir" value="#{config_dir}")
26
+
27
+ %input( type="submit" value="Save" )
@@ -0,0 +1,79 @@
1
+ # Defaults for ajax requests.
2
+ jQuery.ajaxSetup cache: true
3
+
4
+ # Method to highlight a change.
5
+ jQuery.fn.highlight = ->
6
+ this.effect('highlight', 3 * 1000)
7
+
8
+ hello = () ->
9
+ jQuery.getJSON('/hello', (data) ->
10
+ console.log("GET /hello: %o", data)
11
+ )
12
+
13
+ secret = () ->
14
+ data=
15
+ secret: $('#secret').val()
16
+ jQuery.post('/hello', data, (data, textStatus, jqXHR) ->
17
+ console.log("POST /hello: %o %o %o", data, textStatus, jqXHR)
18
+ $('#token').val(data.token)
19
+ token=data.token
20
+ )
21
+
22
+ edit = () ->
23
+ tid = "#text"
24
+ text = $(tid).val()
25
+ url = window.location.toString()
26
+ extension = '.txt'
27
+
28
+ data=
29
+ tid: "#text"
30
+ text: $("#text").val()
31
+ url: url
32
+ extension: $('#extension').val()
33
+ token: $("#token").val()
34
+
35
+ jQuery.post('/edit', data, (data, textStatus, jqXHR) ->
36
+ console.log("POST /edit: %o %o %o", data, textStatus, jqXHR)
37
+ $('#sid').val(data.sid).highlight()
38
+ $('#change-id').val( if data.change_id then data.change_id else 0).highlight()
39
+ )
40
+
41
+ edit_prev = () ->
42
+ tid = "#text"
43
+ url = window.location.toString()
44
+ extension = '.text'
45
+
46
+ data=
47
+ tid: "#text"
48
+ url: url
49
+ extension: $('#extension').val()
50
+ token: $('#token').val()
51
+
52
+ jQuery.post('/edit', data, (data, textStatus, jqXHR) ->
53
+ console.log("POST /edit: %o %o %o", data, textStatus, jqXHR)
54
+ $('#sid').val(data.sid).highlight()
55
+ $('#change-id').val(if data.change_id then data.change_id else 0).highlight()
56
+ )
57
+
58
+ update = () ->
59
+ jQuery.getJSON('/edit/' + $('#sid').val() + "/" + $("#change-id").val(), (data) ->
60
+ console.log("GET /edit/:sid/:change-id: %o", data)
61
+ if data.change_id && data.change_id.toString() != $('#change-id').val()
62
+ $('#text').val(data.text).highlight()
63
+ $('#change-id').val(data.change_id).highlight()
64
+ )
65
+
66
+ preferences = () ->
67
+ event.preventDefault()
68
+ event.stopPropagation()
69
+ window.open('/preferences?token=' + encodeURIComponent($('#token').val()), "iat_prefs")
70
+ return true
71
+
72
+ jQuery ->
73
+ $("#hello-btn").click(hello);
74
+ $("#secret-btn").click(secret);
75
+ $("#edit-btn").click(edit);
76
+ $("#edit-prev-btn").click(edit_prev);
77
+ $("#update-btn").click(update);
78
+ $("#preferences-btn").click(preferences);
79
+
@@ -0,0 +1,94 @@
1
+ !!!
2
+ %meta( charset="utf-8" )
3
+ %title Reference Implementation
4
+ %script( type="text/javascript" src="/jquery.js" )
5
+ %script( type="text/javascript" src="/jquery-ui.js" )
6
+ %script( type="text/javascript" src="script.js" )
7
+ %link( rel="stylesheet" type="text/css" href="style.css" )
8
+ %body
9
+ %h1 Reference Implementation of IAT
10
+
11
+ %p
12
+ This is a reference implementation of IAT's browser side code. See the code on
13
+ %a( href="http://github.com/docwhat/iated" ) GitHub
14
+
15
+ %div#content-text
16
+ %h2 Textarea
17
+ An example textarea to play in.
18
+
19
+ %div#textarea-wrapper
20
+ %textarea#text="Some example text\nto play with."
21
+
22
+ %div#content-data
23
+ %h2 The data
24
+
25
+ %dl
26
+ %dt
27
+ Extension:
28
+ %dd
29
+ %input#extension( name="extension" type="text" value=".txt" )
30
+ %br
31
+ The extension used for the file when opening it up to the editor.
32
+ This value is checked on the server side against the list of approved
33
+ extensions.
34
+
35
+ %dt
36
+ Browser Authentication Secret:
37
+ %dd
38
+ %input#secret( name="secret" type="text" )
39
+ %br
40
+ This is a one-time secret used to verify the browser is actually under
41
+ control of the user who is running Iated.
42
+
43
+ %dt
44
+ Browser Token:
45
+ %dd
46
+ %input#token( name="token" type="text" )
47
+ %br
48
+ This is the unique token to be used by this one browser extension instance
49
+ to validate against Iated.
50
+
51
+ %dt
52
+ Edit Session ID (sid):
53
+ %dd
54
+ %input#sid( name="sid" type="text" )
55
+ %br
56
+ The session identifier for editing this particular textarea.
57
+
58
+ %dt
59
+ Change ID:
60
+ %dd
61
+ %input#change-id( name="change-id" type="text" )
62
+ %br
63
+ Every time the file changes on disk, the change id is incremented. It starts
64
+ at zero when the edit session is created and increments during the lifetime
65
+ of the session.
66
+
67
+ %div#content-requests
68
+ %h2 The requests
69
+
70
+ %ol
71
+ %li
72
+ %button#hello-btn GET /hello
73
+ %br
74
+ Ask for a secret to authenticate
75
+ %li
76
+ %button#secret-btn POST /hello (with secret)
77
+ %br
78
+ Send the secret to retrieve a token.
79
+ %li
80
+ %button#edit-btn POST /edit
81
+ %br
82
+ Request that the text be opened in an editor.
83
+ %li
84
+ %button#edit-prev-btn POST /edit
85
+ %br
86
+ Request the existing file be opened in an editor.
87
+ %li
88
+ %button#update-btn POST /edit/:sid/:change_id
89
+ %br
90
+ Check the status of the edit, retrieving changes as needed.
91
+ %li
92
+ %button#preferences-btn GET /preferences
93
+ %br
94
+ Open the preference window.
@@ -0,0 +1,36 @@
1
+ body {
2
+ font-family: 'Lucida Sans Unicode', 'Lucida Grande', sans-serif;
3
+ background-color: #def;
4
+ }
5
+
6
+ dd {
7
+ font-size: 90%;
8
+ }
9
+
10
+ #content-text {
11
+ margin: 0 1em;
12
+ float: left;
13
+ width: 30%;
14
+ #textarea-wrapper {
15
+ textarea {
16
+ position: fixed;
17
+ left: inherit;
18
+ top: inherit;
19
+ width: 28%;
20
+ height: 8em;
21
+ }
22
+ }
23
+ }
24
+ #content-data {
25
+ margin: 0 1em;
26
+ float: left;
27
+ width: 30%;
28
+ input {
29
+ font-family: Menlo, monospace;
30
+ }
31
+ }
32
+ #content-requests {
33
+ margin: 0 1em;
34
+ float: left;
35
+ width: 30%;
36
+ }
@@ -0,0 +1,13 @@
1
+ !!!
2
+ %meta( charset="utf-8" )
3
+ %title Iated
4
+
5
+ %body( id="root" )
6
+ %h1 It's All Text! editor daemon
7
+
8
+ %dl
9
+ %dt Chrome
10
+ %dd Link to plugin
11
+
12
+ %dt Firefox
13
+ %dd Link to plugin
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'pathname'
3
+ require 'tmpdir'
4
+ require 'fileutils'
5
+
6
+ describe Iated::BrowserTokenDB do
7
+
8
+ it "writes to a specified file" do
9
+ dir = Dir.mktmpdir
10
+ fname = Pathname.new(dir) + 'test.yml'
11
+ db = Iated::BrowserTokenDB.new fname
12
+ fname.exist?.should be_true
13
+ FileUtils.rm_rf dir
14
+ end
15
+
16
+ it "doesn't have tokens that don't exist" do
17
+ dir = Dir.mktmpdir
18
+ fname = Pathname.new(dir) + 'test.yml'
19
+ db = Iated::BrowserTokenDB.new fname
20
+ db.has_token?("random-token").should be_false
21
+ db.user_agent("random_token").should be_nil
22
+ FileUtils.rm_rf dir
23
+ end
24
+
25
+ it "stores tokens and reads them back" do
26
+ dir = Dir.mktmpdir
27
+ ua = "NCSA_Mosaic/2.7b5 (X11;Linux 2.6.7 i686) libwww/2.12"
28
+ fname = Pathname.new(dir) + 'test.yml'
29
+ db = Iated::BrowserTokenDB.new fname
30
+ tok = db.add ua
31
+ db.has_token?(tok).should be_true
32
+ db.user_agent(tok).should == ua
33
+ FileUtils.rm_rf dir
34
+ end
35
+
36
+ it "stores tokens and reads them back persistantly" do
37
+ dir = Dir.mktmpdir
38
+ ua = "NCSA_Mosaic/2.7b5 (X11;Linux 2.6.7 i686) libwww/2.12"
39
+ fname = Pathname.new(dir) + 'test.yml'
40
+ db = Iated::BrowserTokenDB.new fname
41
+ tok = db.add ua
42
+ db = nil
43
+
44
+ db2 = Iated::BrowserTokenDB.new fname
45
+ db2.has_token?(tok).should be_true
46
+ db2.user_agent(tok).should == ua
47
+ FileUtils.rm_rf dir
48
+ end
49
+
50
+ it "tokens are always strings" do
51
+ dir = Dir.mktmpdir
52
+ fname = Pathname.new(dir) + 'test.yml'
53
+ db = Iated::BrowserTokenDB.new fname
54
+ tok = db.add "user agent"
55
+ tok.should be_an_instance_of String
56
+ FileUtils.rm_rf dir
57
+ end
58
+
59
+ it "user agents are always strings" do
60
+ dir = Dir.mktmpdir
61
+ fname = Pathname.new(dir) + 'test.yml'
62
+ db = Iated::BrowserTokenDB.new fname
63
+ tok = db.add :user_agent
64
+ db.user_agent(tok).should be_an_instance_of String
65
+ FileUtils.rm_rf dir
66
+ end
67
+
68
+ end
@@ -0,0 +1,157 @@
1
+ require 'spec_helper'
2
+
3
+ describe Iated::EditSession do
4
+ before(:each) do
5
+ Iated::reset
6
+ end
7
+ after(:each) do
8
+ Iated::purge
9
+ end
10
+
11
+ context "#find" do
12
+
13
+ it "should find existing by params" do
14
+ params = {:url => 'http://example.com/'}
15
+ Iated::EditSession.new(params).should == Iated::EditSession.find(params)
16
+ end
17
+
18
+ it "should find existing sessions by sid" do
19
+ params = {:url => 'http://example.com/'}
20
+ sess1 = Iated::EditSession.new(params)
21
+ sess1.should == Iated::EditSession.find(sess1.sid)
22
+ end
23
+ end
24
+
25
+ context "#find_or_create" do
26
+ it "should find or create by exact match" do
27
+ tid = "fc-tid#{rand(1000)}"
28
+
29
+ sess1 = Iated::EditSession.find_or_create(:url => 'http://example.com/', :tid => tid)
30
+ sess2 = Iated::EditSession.find_or_create(:url => 'http://example.com/', :tid => tid)
31
+
32
+ sess1.should == sess2
33
+ end
34
+ end
35
+
36
+ context "#sid" do
37
+ it "should be 32 character hex string" do
38
+ tok = Iated::EditSession.calculate_sid :url => 'http://example.com/'
39
+ tok.should =~ /^[a-f0-9]{32}$/
40
+ end
41
+
42
+ it "should be different for different extensions" do
43
+ tok1 = Iated::EditSession.calculate_sid :url => "http://example.com", :extension => '.xml'
44
+ tok2 = Iated::EditSession.calculate_sid :url => "http://example.com", :extension => '.txt'
45
+ tok1.should_not == tok2
46
+ end
47
+
48
+ it "should be different for different urls" do
49
+ tok1 = Iated::EditSession.calculate_sid :url => "http://example.com/a"
50
+ tok2 = Iated::EditSession.calculate_sid :url => "http://example.com/b"
51
+ tok1.should_not == tok2
52
+ end
53
+
54
+ it "should be different for different tids" do
55
+ tok1 = Iated::EditSession.calculate_sid :url => "http://example.com/", :tid => 'a'
56
+ tok2 = Iated::EditSession.calculate_sid :url => "http://example.com/", :tid => 'b'
57
+ tok1.should_not == tok2
58
+ end
59
+ end
60
+
61
+ context "#text" do
62
+ it "should save the text when assigned" do
63
+ text = "\t Random Number: #{rand}"
64
+ sess = Iated::EditSession.new :url => 'http://example.com/', :text => text
65
+ sess.filename.should be_exist
66
+ sess.filename.read.should == text
67
+ end
68
+
69
+ it "should read back the text" do
70
+ text = "\t Random Number: #{rand}"
71
+ sess = Iated::EditSession.new :url => 'http://example.com/', :text => text
72
+ sess.text.should == text
73
+ end
74
+
75
+ it "shouldn't touch the change_id on first save" do
76
+ sess = Iated::EditSession.new :url => 'http://example.com/first_save_check', :tid => "#{rand}"
77
+ sess.text = "first-save-foo"
78
+ sess.change_id.should == 0
79
+ end
80
+
81
+ it "should increment the change_id on subsequent saves" do
82
+ sess = Iated::EditSession.new :url => 'http://example.com/subseq_save_check', :tid => "#{rand}", :text => "sub-foo"
83
+ sess.text = "sub-bar"
84
+ sess.change_id.should == 1
85
+ end
86
+
87
+ it "should be writen to disk" do
88
+ sess = Iated::EditSession.new :url => 'http://example.com/writeme', :tid => "#{rand}", :text => "written"
89
+ sess.filename.open('r') do |f|
90
+ f.read.should == "written"
91
+ end
92
+ end
93
+ end
94
+
95
+ context "#change_id" do
96
+ it "should be zero for new sessions" do
97
+ params = {}
98
+ params[:text] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
99
+ params[:url] = "http://example.com/cucumber"
100
+ session = Iated::EditSession.new params
101
+ session.change_id.should == 0
102
+ end
103
+
104
+ it "should detect the change_id when the contents change" do
105
+ sess = Iated::EditSession.new :url => 'http://example.com/changer', :tid => "#{rand}", :text => "change me"
106
+ sess.change_id.should == 0
107
+ sess.filename.open('w') do |f|
108
+ f.write "I'm changed!"
109
+ end
110
+ sess.change_id.should == 1
111
+ end
112
+ end
113
+
114
+ context "#increment_change_id" do
115
+ it "should increment the #change_id" do
116
+ sess = Iated::EditSession.new :url => 'http://example.com/should_increment'
117
+ sess.change_id.should == 0
118
+ sess.increment_change_id
119
+ sess.change_id.should == 1
120
+ end
121
+ end
122
+
123
+ context "param normalization" do
124
+ it "should handle text keys the same as symbol keys" do
125
+ [:url, :tid, :extension, :text].each do |key|
126
+ h1 = {}
127
+ h1[key] = 'stuff'
128
+ h2 = {}
129
+ h2[key.to_s] = 'stuff'
130
+ p1 = Iated::EditSession.normalize_keys h1
131
+ p2 = Iated::EditSession.normalize_keys h2
132
+ p1.should == p2
133
+ end
134
+ end
135
+
136
+ it "should not destroy the original" do
137
+ original = {
138
+ :url => "http://example.com/",
139
+ :tid => "some-tid",
140
+ }
141
+ normalized = Iated::EditSession.normalize_keys original
142
+ original.should_not be_nil
143
+ end
144
+
145
+ it "should strip :text being passed in" do
146
+ original = {
147
+ :url => "http://example.com/",
148
+ :text => "some text",
149
+ :tid => "some-tid",
150
+ }
151
+ normalized = Iated::EditSession.normalize_keys original
152
+ normalized[:url].should == original[:url]
153
+ normalized[:tid].should == original[:tid]
154
+ normalized[:text].should be_nil
155
+ end
156
+ end
157
+ end