iated 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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