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.
- data/.gitignore +6 -0
- data/Gemfile +3 -0
- data/Guardfile +24 -0
- data/LICENSE +23 -0
- data/Makefile +72 -0
- data/README.md +87 -0
- data/Rakefile +10 -0
- data/bin/iated +13 -0
- data/config.ru +5 -0
- data/extensions/chrome/background.html +5 -0
- data/extensions/chrome/background.js +105 -0
- data/extensions/chrome/contentscript.css +0 -0
- data/extensions/chrome/contentscript.js +110 -0
- data/extensions/chrome/jquery-ui.js +45 -0
- data/extensions/chrome/jquery.js +16 -0
- data/extensions/chrome/jquery.updater.js +46 -0
- data/extensions/chrome/manifest.json +19 -0
- data/extensions/chrome/yaml.js +489 -0
- data/extensions/tests/simple.html +23 -0
- data/features/extension_authenticates.feature +30 -0
- data/features/extension_edits.feature +45 -0
- data/features/step_definitions/extension_steps.rb +134 -0
- data/features/support/env.rb +47 -0
- data/features/support/hooks.rb +11 -0
- data/iated.gemspec +48 -0
- data/lib/iated.rb +111 -0
- data/lib/iated/browser_token_db.rb +76 -0
- data/lib/iated/edit_session.rb +221 -0
- data/lib/iated/helpers.rb +9 -0
- data/lib/iated/mcp.rb +144 -0
- data/lib/iated/page_helpers.rb +33 -0
- data/lib/iated/public/jquery-ui.js +101 -0
- data/lib/iated/public/jquery.js +2 -0
- data/lib/iated/public/robots.txt +5 -0
- data/lib/iated/server.rb +162 -0
- data/lib/iated/sys_pref.rb +201 -0
- data/lib/iated/version.rb +3 -0
- data/lib/iated/views/hello.haml +13 -0
- data/lib/iated/views/preferences.haml +27 -0
- data/lib/iated/views/reference.coffee +79 -0
- data/lib/iated/views/reference.haml +94 -0
- data/lib/iated/views/reference.scss +36 -0
- data/lib/iated/views/root.haml +13 -0
- data/spec/lib/iated/browser_token_db_spec.rb +68 -0
- data/spec/lib/iated/edit_session_spec.rb +157 -0
- data/spec/lib/iated/mcp_spec.rb +86 -0
- data/spec/lib/iated/sys_pref_spec.rb +40 -0
- data/spec/protocol/edit_spec.rb +88 -0
- data/spec/protocol/hello_spec.rb +18 -0
- data/spec/protocol/notfound_spec.rb +11 -0
- data/spec/protocol/ping_spec.rb +10 -0
- data/spec/protocol/preferences_spec.rb +35 -0
- data/spec/spec_helper.rb +21 -0
- metadata +460 -0
@@ -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,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
|