cloudkey 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 +3 -0
- data/Gemfile +4 -0
- data/Rakefile +9 -0
- data/Readme.md +31 -0
- data/cloudkey.gemspec +24 -0
- data/lib/cloudkey.rb +12 -0
- data/lib/cloudkey/api.rb +86 -0
- data/lib/cloudkey/client.rb +45 -0
- data/lib/cloudkey/file.rb +29 -0
- data/lib/cloudkey/media.rb +13 -0
- data/lib/cloudkey/security_level.rb +14 -0
- data/lib/cloudkey/security_policy.rb +100 -0
- data/lib/cloudkey/version.rb +3 -0
- data/spec/cloudkey/api_spec.rb +52 -0
- data/spec/cloudkey/security_policy_spec.rb +53 -0
- data/spec/cloudkey_spec.rb +25 -0
- data/spec/spec_helper.rb +1 -0
- metadata +119 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Rakefile
ADDED
data/Readme.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
Cloudkey
|
2
|
+
========
|
3
|
+
|
4
|
+
Introduction
|
5
|
+
------------
|
6
|
+
|
7
|
+
This gem, still under development, aims to provide an abstract interface to DailyMotion's Cloud service.
|
8
|
+
Currently, it's mostly a rewrite of the Python and Php version.
|
9
|
+
|
10
|
+
Warning
|
11
|
+
-------
|
12
|
+
|
13
|
+
We were not able to use security features from the web service to craft restricted urls while testing the Python
|
14
|
+
or PHP versions, so we supposed they had not been activated yet.
|
15
|
+
|
16
|
+
Usage
|
17
|
+
-----
|
18
|
+
|
19
|
+
# Fill in your credentials
|
20
|
+
@cloudkey = Cloudkey.authenticate USER_ID, KEY
|
21
|
+
|
22
|
+
# Grab a list of your medias
|
23
|
+
p @cloudkey.media.list(:fields => [:id])
|
24
|
+
|
25
|
+
# Get an embedded player for your video, with its usage restricted to a specific IP address
|
26
|
+
p @cloudkey.media.embedded_url VIDEO_ID, Cloudkey::SecurityPolicy.new(:ip => "88.0.0.1")
|
27
|
+
|
28
|
+
License
|
29
|
+
-------
|
30
|
+
|
31
|
+
Cloudkey is released under the MIT License.
|
data/cloudkey.gemspec
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "cloudkey/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "cloudkey"
|
7
|
+
s.version = Cloudkey::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Jean-Hadrien Chabran", "Boubacar Diallo"]
|
10
|
+
s.email = ["jh@kareea.com"]
|
11
|
+
s.homepage = "http://rubygems.org/gems/cloudkey"
|
12
|
+
s.summary = %q{Bla bla}
|
13
|
+
s.description = %q{bla bla}
|
14
|
+
|
15
|
+
s.rubyforge_project = "cloudkey"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency "rspec", "~> 2.0.1"
|
23
|
+
s.add_dependency 'curb', "~> 0.7.8"
|
24
|
+
end
|
data/lib/cloudkey.rb
ADDED
data/lib/cloudkey/api.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
require 'cloudkey/client'
|
4
|
+
|
5
|
+
require 'cloudkey/file'
|
6
|
+
require 'cloudkey/media'
|
7
|
+
|
8
|
+
module Cloudkey
|
9
|
+
class API
|
10
|
+
attr_accessor :user_id, :key, :base_url, :proxy, :act_as_user
|
11
|
+
attr_reader :target
|
12
|
+
|
13
|
+
# New API versions that break compatibility would probably change the endpoint
|
14
|
+
END_POINT = "/api"
|
15
|
+
|
16
|
+
def initialize user_id, key, options={}
|
17
|
+
raise "Can't connect without an user_id" unless user_id
|
18
|
+
raise "Can't connect without an key" unless key
|
19
|
+
|
20
|
+
@user_id, @key = user_id, key
|
21
|
+
|
22
|
+
@base_url = options[:base_url] || 'http://api.dmcloud.net'
|
23
|
+
@proxy = options[:proxy]
|
24
|
+
@act_as_user = options[:act_as_user]
|
25
|
+
|
26
|
+
@target = @base_url + END_POINT
|
27
|
+
end
|
28
|
+
|
29
|
+
def user_infos
|
30
|
+
if act_as_user
|
31
|
+
"#{user_id}/#{act_as_user}"
|
32
|
+
else
|
33
|
+
user_id
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def media
|
38
|
+
Media.new self
|
39
|
+
end
|
40
|
+
|
41
|
+
def file
|
42
|
+
File.new self
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.sign message, secret
|
46
|
+
Digest::MD5.hexdigest(message + secret)
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.sign_url url, secret, security_policy = SecurityPolicy.new
|
50
|
+
(url, query) = url.split("?")
|
51
|
+
|
52
|
+
expires = security_policy.expires.to_s
|
53
|
+
|
54
|
+
rand = (('a'..'z').to_a + (1..9).to_a).shuffle[0..7].join('')
|
55
|
+
food = security_policy.level.to_s
|
56
|
+
food << url << expires.to_s
|
57
|
+
food << rand << secret << security_policy.private_parameters.join('')
|
58
|
+
food << security_policy.encoded_public_parameters if security_policy.encoded_public_parameters
|
59
|
+
|
60
|
+
digest = Digest::MD5.hexdigest(food)
|
61
|
+
|
62
|
+
result = url
|
63
|
+
result << "?"
|
64
|
+
result << query + '&' if query
|
65
|
+
result << "auth="
|
66
|
+
result << expires.to_s << "-"
|
67
|
+
result << security_policy.level.to_s << "-"
|
68
|
+
result << rand << "-"
|
69
|
+
result << digest
|
70
|
+
result << "-#{security_policy.encoded_public_parameters}" if security_policy.encoded_public_parameters
|
71
|
+
|
72
|
+
result
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.normalize payload
|
76
|
+
case payload
|
77
|
+
when Array
|
78
|
+
payload.collect { |element| normalize element }.join('')
|
79
|
+
when Hash
|
80
|
+
payload.to_a.sort { |a,b| a.first <=> b.first }.collect {|array| array.first.to_s + normalize(array.last)}.join('')
|
81
|
+
else
|
82
|
+
payload.to_s
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Cloudkey
|
4
|
+
class Client
|
5
|
+
def initialize api
|
6
|
+
@api = api
|
7
|
+
end
|
8
|
+
|
9
|
+
def method_missing method_id, *args, &block
|
10
|
+
call(method_id, *args, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
def call method, args={}
|
15
|
+
@request = create_request self.class.name.gsub("Cloudkey::",'').downcase, method, args
|
16
|
+
authenticate_request @request
|
17
|
+
|
18
|
+
curl do |c|
|
19
|
+
c.http_post @request.to_json
|
20
|
+
JSON.parse c.body_str
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def authenticate_request request
|
25
|
+
request[:auth] = "#{@api.user_infos}:#{API::sign(@api.user_infos + API.normalize(request), @api.key)}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def curl url=nil, &block
|
29
|
+
c = Curl::Easy.new(url || @api.target) do |c|
|
30
|
+
c.useragent = "cloudkey-rb #{Cloudkey::VERSION}"
|
31
|
+
c.headers['Content-Type'] = "application/json"
|
32
|
+
c.proxy_url = @api.proxy if @api.proxy
|
33
|
+
end
|
34
|
+
|
35
|
+
yield c
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_request name, method, args
|
39
|
+
{
|
40
|
+
:call => "#{name}.#{method}",
|
41
|
+
:args => args
|
42
|
+
}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Cloudkey
|
2
|
+
class File < Client
|
3
|
+
def upload_file path, &block
|
4
|
+
raise "File not found" unless ::File.exists? path
|
5
|
+
|
6
|
+
curl(fetch_upload_url) do |c|
|
7
|
+
puts "upload! #{c.url}"
|
8
|
+
c.multipart_form_post = true
|
9
|
+
c.headers = false
|
10
|
+
c.follow_location = true
|
11
|
+
if block_given?
|
12
|
+
c.on_progress do |dl_total, dl_now, ul_total, ul_now|
|
13
|
+
block.call(ul_now, ul_total) if ul_total > 0.0
|
14
|
+
true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
c.http_post Curl::PostField.file("file", path)
|
19
|
+
JSON.parse c.body_str
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def fetch_upload_url
|
26
|
+
upload["result"]["url"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Cloudkey
|
2
|
+
class Media < Client
|
3
|
+
def embedded_url id, security_level = SecurityPolicy.new
|
4
|
+
url = "#{@api.base_url}/embed/#{@api.user_id}/#{id}"
|
5
|
+
API.sign_url url, @api.key, security_level
|
6
|
+
end
|
7
|
+
|
8
|
+
def stream_url id, asset_name="mp4_h264_aac", security_level=SecurityPolicy.new, cdn_url='http://cdn.dmcloud.net'
|
9
|
+
url = "#{cdn_url}/route/#{@api.user_id}/#{id}/#{asset_name}.#{asset_name.split('_')[0]}"
|
10
|
+
API.sign_url url, @api.key, security_level
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "base64"
|
3
|
+
require "zlib"
|
4
|
+
|
5
|
+
module Cloudkey
|
6
|
+
class SecurityPolicy
|
7
|
+
IP_FORMAT_ERROR = Class.new(Exception)
|
8
|
+
REFERERS_FORMAT_ERROR = Class.new(Exception)
|
9
|
+
|
10
|
+
def initialize opts={}
|
11
|
+
@options = {:expires_in => 7200}.merge(opts)
|
12
|
+
end
|
13
|
+
|
14
|
+
def method_missing method_id, *args, &block
|
15
|
+
method_id = method_id.to_s
|
16
|
+
|
17
|
+
affectation = method_id.include? "="
|
18
|
+
method_id.gsub!("=",'')
|
19
|
+
|
20
|
+
if affectation
|
21
|
+
@options[method_id.to_sym] = args.first
|
22
|
+
end
|
23
|
+
|
24
|
+
@options[method_id.to_sym]
|
25
|
+
end
|
26
|
+
|
27
|
+
def expires
|
28
|
+
@options[:expires_in] + Time.now.tv_sec
|
29
|
+
end
|
30
|
+
|
31
|
+
def none?
|
32
|
+
@options.empty? || @options.keys == [:expires_in]
|
33
|
+
end
|
34
|
+
|
35
|
+
def delegate?
|
36
|
+
@options[:delegate]
|
37
|
+
end
|
38
|
+
|
39
|
+
def as_number?
|
40
|
+
!!@options[:as_number]
|
41
|
+
end
|
42
|
+
|
43
|
+
def ip?
|
44
|
+
if @options[:ip]
|
45
|
+
raise IP_FORMAT_ERROR unless @options[:ip].match(/\b(?:\d{1,3}\.){3}\d{1,3}\b/)
|
46
|
+
true
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def user_agent?
|
51
|
+
@options[:user_agent] && !@options[:user_agent].empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def use_once?
|
55
|
+
@options[:use_once]
|
56
|
+
end
|
57
|
+
|
58
|
+
def countries?
|
59
|
+
@options[:countries] && !@options[:countries].empty?
|
60
|
+
end
|
61
|
+
|
62
|
+
def referers?
|
63
|
+
if @options[:referers] && !@options[:referers].empty?
|
64
|
+
raise REFERERS_FORMAT_ERROR unless @options[:referers].inject(true) { |result, url| result && url.match(/https?:\/\/(.*)/) }
|
65
|
+
true
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def set opts={}
|
70
|
+
@options = opts
|
71
|
+
end
|
72
|
+
|
73
|
+
def private_parameters
|
74
|
+
parameters = []
|
75
|
+
parameters << as_number if as_number?
|
76
|
+
parameters << ip if ip?
|
77
|
+
parameters << user_agent if user_agent?
|
78
|
+
parameters
|
79
|
+
end
|
80
|
+
|
81
|
+
def public_parameters
|
82
|
+
parameters = []
|
83
|
+
parameters << "cc=#{countries.collect{|c| c.downcase}.join(',')}" if countries?
|
84
|
+
parameters << "rf=#{CGI.escape(referers.collect{|r| r.gsub(' ', '%20')}.join(' '))}" if referers?
|
85
|
+
parameters unless parameters.empty?
|
86
|
+
end
|
87
|
+
|
88
|
+
def encoded_public_parameters
|
89
|
+
Base64.encode64(Zlib::Deflate.deflate(public_parameters.join('&'))).chomp if public_parameters
|
90
|
+
end
|
91
|
+
|
92
|
+
def level
|
93
|
+
result = 0
|
94
|
+
API::SecurityLevel.constants.each do |constant|
|
95
|
+
result |= API::SecurityLevel.const_get(constant) if send("#{constant.to_s.downcase}?")
|
96
|
+
end
|
97
|
+
result
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Cloudkey::API do
|
4
|
+
describe "Authentication" do
|
5
|
+
it "should raise an error without an user_id" do
|
6
|
+
lambda {Cloudkey::API.new nil, "foobar"}.should raise_error
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should raise an error without an api_key" do
|
10
|
+
lambda {Cloudkey::API.new "bob", nil}.should raise_error
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "Helpers methods" do
|
15
|
+
before(:each) do
|
16
|
+
@api = Cloudkey::API.new "foo", "bar"
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return Cloudkey::File when sending :file" do
|
20
|
+
@api.file.should be_an_instance_of(Cloudkey::File)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should return Cloudkey::Media when sending :media" do
|
24
|
+
@api.media.should be_an_instance_of(Cloudkey::Media)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "Normalizing" do
|
29
|
+
{
|
30
|
+
'foo42bar' => ['foo', 42, 'bar'],
|
31
|
+
'pink3red2yellow1' => {'yellow' => 1, 'red' => 2, 'pink' => 3},
|
32
|
+
'foo42pink3red2yellow1bar' => ['foo', 42, {'yellow' => 1, 'red' => 2, 'pink' => 3}, 'bar'],
|
33
|
+
'12' => [nil, 1,2],
|
34
|
+
'' => nil,
|
35
|
+
'212345' => {2 => [nil, 1,2], 3 => nil, 4 => 5}
|
36
|
+
}.each do |normalized, original|
|
37
|
+
it "should normalize #{original.inspect} into #{normalized}" do
|
38
|
+
Cloudkey::API.normalize(original).should == normalized
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "Signing" do
|
44
|
+
it "should sign 'hello world' with sEcReT_KeY and returns 'b5d93121a6dc87562b46beb8ba809ace'" do
|
45
|
+
Cloudkey::API.sign("hello world", "sEcReT_KeY").should == 'b5d93121a6dc87562b46beb8ba809ace'
|
46
|
+
end
|
47
|
+
|
48
|
+
it "it should sign an url" do
|
49
|
+
Cloudkey::API.sign_url("http://google.fr","olol", Cloudkey::SecurityPolicy.new(:ip => "192.168.0.1"))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
module Cloudkey
|
4
|
+
describe SecurityPolicy do
|
5
|
+
before(:each) do
|
6
|
+
@policy = SecurityPolicy.new
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "Default behavior" do
|
10
|
+
it "should default to no policy" do
|
11
|
+
@policy.should be_none
|
12
|
+
@policy.expires_in.should == 7200
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "IP" do
|
17
|
+
it "should accept an IP" do
|
18
|
+
@policy.ip = "192.168.0.3"
|
19
|
+
(@policy.level & API::SecurityLevel::IP).should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should accept an IP and a user agent" do
|
23
|
+
@policy.set :ip => "192.168.0.1", :user_agent => "Mammouth Browser v0.1"
|
24
|
+
(@policy.level & API::SecurityLevel::IP).should be_true
|
25
|
+
(@policy.level & API::SecurityLevel::USER_AGENT).should be_true
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should raise an error on bad ip format" do
|
29
|
+
@policy.set :ip => "Bob Kelso"
|
30
|
+
-> {@policy.level}.should raise_error(SecurityPolicy::IP_FORMAT_ERROR)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "Referers" do
|
35
|
+
it "should accept referers" do
|
36
|
+
@policy.referers = %w(http://google.com http://lolcat.com)
|
37
|
+
(@policy.level & API::SecurityLevel::REFERERS).should be_true
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should accept only valid refers" do
|
41
|
+
@policy.referers = ["http://google.com", ""]
|
42
|
+
-> { @policy.level }.should raise_error(SecurityPolicy::REFERERS_FORMAT_ERROR)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "Expires" do
|
47
|
+
it "should accept an expire time" do
|
48
|
+
@policy.expires_in = 5000
|
49
|
+
@policy.expires_in.should be(5000)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Cloudkey do
|
4
|
+
context "Public API" do
|
5
|
+
it "should provide an authenticate method on Cloudkey" do
|
6
|
+
Cloudkey.should respond_to :authenticate
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should count medias" do
|
10
|
+
pending
|
11
|
+
@cloudkey = Cloudkey.authenticate "foo", "bar"
|
12
|
+
@cloudkey.media.count
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should accept an optional proxy" do
|
16
|
+
@proxy = "http://my.awesome.proxy.com:3128"
|
17
|
+
Cloudkey.authenticate("foo", "bar", :proxy => @proxy).proxy.should == @proxy
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should accept an optional base_url" do
|
21
|
+
@base_url = "http://different.api.dmcloud.net"
|
22
|
+
Cloudkey.authenticate("foo", "bar", :base_url => @base_url).base_url.should == @base_url
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'cloudkey'
|
metadata
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cloudkey
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Jean-Hadrien Chabran
|
14
|
+
- Boubacar Diallo
|
15
|
+
autorequire:
|
16
|
+
bindir: bin
|
17
|
+
cert_chain: []
|
18
|
+
|
19
|
+
date: 2010-11-15 00:00:00 +01:00
|
20
|
+
default_executable:
|
21
|
+
dependencies:
|
22
|
+
- !ruby/object:Gem::Dependency
|
23
|
+
name: rspec
|
24
|
+
prerelease: false
|
25
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ~>
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
hash: 13
|
31
|
+
segments:
|
32
|
+
- 2
|
33
|
+
- 0
|
34
|
+
- 1
|
35
|
+
version: 2.0.1
|
36
|
+
type: :development
|
37
|
+
version_requirements: *id001
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: curb
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ~>
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
hash: 19
|
47
|
+
segments:
|
48
|
+
- 0
|
49
|
+
- 7
|
50
|
+
- 8
|
51
|
+
version: 0.7.8
|
52
|
+
type: :runtime
|
53
|
+
version_requirements: *id002
|
54
|
+
description: bla bla
|
55
|
+
email:
|
56
|
+
- jh@kareea.com
|
57
|
+
executables: []
|
58
|
+
|
59
|
+
extensions: []
|
60
|
+
|
61
|
+
extra_rdoc_files: []
|
62
|
+
|
63
|
+
files:
|
64
|
+
- .gitignore
|
65
|
+
- Gemfile
|
66
|
+
- Rakefile
|
67
|
+
- Readme.md
|
68
|
+
- cloudkey.gemspec
|
69
|
+
- lib/cloudkey.rb
|
70
|
+
- lib/cloudkey/api.rb
|
71
|
+
- lib/cloudkey/client.rb
|
72
|
+
- lib/cloudkey/file.rb
|
73
|
+
- lib/cloudkey/media.rb
|
74
|
+
- lib/cloudkey/security_level.rb
|
75
|
+
- lib/cloudkey/security_policy.rb
|
76
|
+
- lib/cloudkey/version.rb
|
77
|
+
- spec/cloudkey/api_spec.rb
|
78
|
+
- spec/cloudkey/security_policy_spec.rb
|
79
|
+
- spec/cloudkey_spec.rb
|
80
|
+
- spec/spec_helper.rb
|
81
|
+
has_rdoc: true
|
82
|
+
homepage: http://rubygems.org/gems/cloudkey
|
83
|
+
licenses: []
|
84
|
+
|
85
|
+
post_install_message:
|
86
|
+
rdoc_options: []
|
87
|
+
|
88
|
+
require_paths:
|
89
|
+
- lib
|
90
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
91
|
+
none: false
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
hash: 3
|
96
|
+
segments:
|
97
|
+
- 0
|
98
|
+
version: "0"
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
hash: 3
|
105
|
+
segments:
|
106
|
+
- 0
|
107
|
+
version: "0"
|
108
|
+
requirements: []
|
109
|
+
|
110
|
+
rubyforge_project: cloudkey
|
111
|
+
rubygems_version: 1.3.7
|
112
|
+
signing_key:
|
113
|
+
specification_version: 3
|
114
|
+
summary: Bla bla
|
115
|
+
test_files:
|
116
|
+
- spec/cloudkey/api_spec.rb
|
117
|
+
- spec/cloudkey/security_policy_spec.rb
|
118
|
+
- spec/cloudkey_spec.rb
|
119
|
+
- spec/spec_helper.rb
|