Class: GitLfsS3::Application

Inherits:
Sinatra::Application
  • Object
show all
Includes:
AwsHelpers
Defined in:
lib/git-lfs-s3/application.rb

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from AwsHelpers

#aws_access_key_id, #aws_region, #aws_secret_access_key, #bucket, #bucket_name, #object_data, #s3

Class Attribute Details

.auth_callbackObject (readonly)

Returns the value of attribute auth_callback.



8
9
10
# File 'lib/git-lfs-s3/application.rb', line 8

def auth_callback
  @auth_callback
end

Class Method Details

.authentication_enabled?Boolean

Returns:

  • (Boolean)


14
15
16
# File 'lib/git-lfs-s3/application.rb', line 14

def authentication_enabled?
  !auth_callback.nil?
end

.on_authenticate(&block) ⇒ Object



10
11
12
# File 'lib/git-lfs-s3/application.rb', line 10

def on_authenticate(&block)
  @auth_callback = block
end

.perform_authentication(username, password, is_safe) ⇒ Object



18
19
20
# File 'lib/git-lfs-s3/application.rb', line 18

def perform_authentication(username, password, is_safe)
  auth_callback.call(username, password, is_safe)
end

Instance Method Details

#authorized?Boolean

Returns:

  • (Boolean)


34
35
36
37
38
39
# File 'lib/git-lfs-s3/application.rb', line 34

def authorized?
  @auth ||=  Rack::Auth::Basic::Request.new(request.env)
  @auth.provided? && @auth.basic? && @auth.credentials && self.class.auth_callback.call(
    @auth.credentials[0], @auth.credentials[1], request.safe?
  )
end

#download(authenticated, params) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/git-lfs-s3/application.rb', line 115

def download(authenticated, params)
  # Handle git-lfs batch downloads.
  objects = []
  params[:objects].each do |obj_json|
    obj_json = indifferent_params(obj_json)
    obj = object_data(obj_json[:oid])
    if valid_obj?(obj_json)
      if obj.exists?
        objects.push(obj_download(authenticated, obj, obj_json))
      else
        objects.push(obj_error(404, 'Object does not exist', obj_json))
      end
    else
      objects.push(obj_error(422, 'Validation error', obj_json))
    end
  end
  objects
end

#error_resp(status_code, message) ⇒ Object



163
164
165
166
167
168
169
170
171
# File 'lib/git-lfs-s3/application.rb', line 163

def error_resp(status_code, message)
  # Error git-lfs batch response.
  status(status_code)
  resp = {
    'message' => message,
    'request_id' => SecureRandom::uuid
  }
  body MultiJson.dump(resp)
end

#expire_atObject



62
63
64
# File 'lib/git-lfs-s3/application.rb', line 62

def expire_at()
  DateTime.now.next_day.to_time.utc.iso8601
end

#lfs_resp(objects) ⇒ Object



153
154
155
156
157
158
159
160
161
# File 'lib/git-lfs-s3/application.rb', line 153

def lfs_resp(objects)
  # Successful git-lfs batch response.
  status(200)
  resp = {
    'transfer' => 'basic',
    'objects' => objects
  }
  body MultiJson.dump(resp)
end

#obj_download(authenticated, obj, obj_json) ⇒ Object



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/git-lfs-s3/application.rb', line 66

def obj_download(authenticated, obj, obj_json)
  # Format a single download object.
  oid = obj_json[:oid]
  size = obj_json[:size]
  {
    'oid'           => oid,
    'size'          => size,
    'authenticated' => authenticated,
    'actions'       => {
      'download'  => {
        'href'  => obj.presigned_url(:get,
                                     :expires_in => 86400),
      },
    },
    'expires_at'    => expire_at,
  }
end

#obj_error(error, message, obj_json) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
# File 'lib/git-lfs-s3/application.rb', line 103

def obj_error(error, message, obj_json)
  # Format a single error object.
  {
    'oid'         => obj_json[:oid],
    'size'        => obj_json[:size],
    'error'       => {
      'code'    => error,
      'message' => message,
    },
  }
end

#obj_upload(authenticated, obj, obj_json) ⇒ Object



84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/git-lfs-s3/application.rb', line 84

def obj_upload(authenticated, obj, obj_json)
  # Format a single upload object.
  oid = obj_json[:oid]
  size = obj_json[:size]
  {
    'oid'           => oid,
    'size'          => size,
    'authenticated' => authenticated,
    'actions'       => {
      'upload'    => {
        'href'  => obj.presigned_url(:put,
                                     acl: 'public-read',
                                     :expires_in => 86400),
      },
      'expires_at'  => expire_at,
    },
  }
end

#protected!Object



41
42
43
44
45
46
# File 'lib/git-lfs-s3/application.rb', line 41

def protected!
  unless authorized?
    response['WWW-Authenticate'] = %(Basic realm="Restricted Area")
    throw(:halt, [401, "Invalid username or password"])
  end
end

#public_read_grantObject



217
218
219
220
221
222
# File 'lib/git-lfs-s3/application.rb', line 217

def public_read_grant
  grantee = Aws::S3::Types::Grantee.new(
    display_name: nil, email_address: nil, id: nil, type: nil,
    uri: "http://acs.amazonaws.com/groups/global/AllUsers")
  Aws::S3::Types::Grant.new(grantee: grantee, permission: "READ")
end

#upload(authenticated, params) ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/git-lfs-s3/application.rb', line 134

def upload(authenticated, params)
# Handle git-lfs batch uploads.
objects = []
params[:objects].each do |obj_json|
  obj_json = indifferent_params(obj_json)
  obj = object_data(obj_json[:oid])
  if valid_obj?(obj_json)
    if obj.exists?
      objects.push(obj_download(authenticated, obj, obj_json))
    else
      objects.push(obj_upload(authenticated, obj, obj_json))
    end
  else
    objects.push(obj_error(422, 'Validation error', obj_json))
  end
end
objects
end

#valid_obj?(obj) ⇒ Boolean

Returns:

  • (Boolean)


52
53
54
55
56
57
58
59
60
# File 'lib/git-lfs-s3/application.rb', line 52

def valid_obj?(obj)
  # Validate that size >= 0 and oid is a SHA256 hash.
  begin
    if obj[:size] >= 0
      oid = obj[:oid]
      valid = (oid.hex.size <= 32) and (oid.size == 64) and (oid =~ /^[0-9a-f]+$/)
    end
  end
end