Class: Onlyoffice::DocsIntegrationSdk::Jwt

Inherits:
Object
  • Object
show all
Extended by:
T::Sig
Includes:
JwtCoding
Defined in:
lib/onlyoffice/docs_integration_sdk/jwt.rb

Overview

Jwt is an implementation of the JwtCoding interface. Under the hood, it uses Ruby JWT library to encode and decode JSON Web Tokens.

This class has its own set of known claims. If an unfamiliar claim is passed to the class during its initialization, it will not be considered.

Before the encoding process by Ruby JWT, this class forms a claims list. The ExpClaim will be included in the list only if its ExpClaim#ttl is not zero, otherwise it will be ignored.

Before the decoding process by Ruby JWT, this class forms a claims list. The ExpClaim will be included in the list only if its ExpClaim#leeway is not zero, otherwise it will be ignored.

RFC 7519 Reference, Ruby JWT Reference

Since:

  • 0.1.0

Defined Under Namespace

Modules: Claim Classes: ExpClaim, IatClaim

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(secret:, algorithm: "HS256", claims: [ExpClaim.new, IatClaim.new]) ⇒ void

initialize initializes a new Jwt instance. It makes a shallow copy of the claims list.

Parameters:

  • secret (String) —

    The secret key used to encode and decode JWTs.

  • algorithm (String) (defaults to: "HS256") —

    The algorithm used to encode and decode JWTs.

  • claims (Array<Claim>) (defaults to: [ExpClaim.new, IatClaim.new]) —

    The list of claims to add to the JWT.

Since:

  • 0.1.0



222
223
224
225
226
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 222

def initialize(secret:, algorithm: "HS256", claims: [ExpClaim.new, IatClaim.new])
  @secret = secret
  @algorithm = algorithm
  @claims = T.let(claims.clone, T::Array[Claim])
end

Instance Attribute Details

#algorithm ⇒ String (readonly)

algorithm is the algorithm used to encode and decode JWTs.

Returns:

  • (String)

Since:

  • 0.1.0



206
207
208
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 206

def algorithm
  @algorithm
end

#claims ⇒ Array<Claim> (readonly)

claims is the list of claims to add to the JWT.

Returns:

Since:

  • 0.1.0



212
213
214
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 212

def claims
  @claims
end

#secret ⇒ String (readonly)

secret is the secret key used to encode and decode JWTs.

Returns:

  • (String)

Since:

  • 0.1.0



200
201
202
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 200

def secret
  @secret
end

Instance Method Details

#decode(t) ⇒ Hash{T.untyped => T.untyped}

decode decodes a token.

Examples:

payload = jwt.decode(token)

Parameters:

  • t (String) —

    The token to decode.

Returns:

  • (Hash{T.untyped => T.untyped}) —

    A decoded token.

Raises:

  • Inherited from JWT.decode of Ruby JWT.

Since:

  • 0.1.0



426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 426

def decode(t)
  o = T.let({}, T::Hash[Symbol, T.untyped])

  o[:algorithm] = @algorithm

  for c in @claims
    if c.is_a?(ExpClaim) && c.leeway != 0
      o[:exp_leeway] = c.leeway
      next
    end
  end

  d, _ = JWT.decode(t, @secret, true, o)
  d = T.cast(d, T::Hash[T.untyped, T.untyped])

  d.delete("exp")
  d.delete("iat")

  d
end

#decode_body(b) ⇒ Hash{T.untyped => T.untyped}

decode_body decodes a body by extracting a token from the body. This method returns a shallow copy of the body with the token removed. It does not modify the original body.

Examples:

json = JSON.parse(res.body)
payload = jwt.decode_body(json)

Parameters:

  • b (Hash{T.untyped => T.untyped}) —

    The body to decode.

Returns:

  • (Hash{T.untyped => T.untyped}) —

    A decoded body.

Raises:

  • (KeyError) —

    If the body does not have a ‘token’ key.

  • (TypeError) —

    If the ‘token’ key is not a String.

  • Inherited from #decode.

Since:

  • 0.1.0



404
405
406
407
408
409
410
411
412
413
414
415
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 404

def decode_body(b)
  if !b.key?("token")
    raise KeyError, "Expected the body to have a 'token' key, but it did not"
  end

  t = b["token"]
  if !t.is_a?(String)
    raise TypeError, "Expected the 'token' key to be a String, but it was a #{t.class}"
  end

  decode(t)
end

#decode_header(h) ⇒ T.untyped

decode_header decodes a header.

Examples:

header = "Bearer ***"
payload = jwt.decode_header(header[7..])

Parameters:

  • h (String) —

    The header to decode

Returns:

  • (T.untyped) —

    A decoded header

Raises:

  • (KeyError) —

    If the decoded header does not have a ‘payload’ key.

  • Inherited from #decode.

Since:

  • 0.1.0



381
382
383
384
385
386
387
388
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 381

def decode_header(h)
  d = decode(h)
  if !d.key?("payload")
    raise KeyError, "Expected the decoded header to have a 'payload' key, but it did not"
  end

  d["payload"]
end

#decode_uri(u) ⇒ URI::HTTP

decode_uri decodes a URI by extracting a token from the query string. This method returns a shallow copy of the URI with the token removed. It does not modify the original URI.

Examples:

uri = jwt.decode_uri(uri)

Parameters:

  • u (URI::HTTP) —

    The URI to decode

Returns:

  • (URI::HTTP) —

    A decoded URI

Raises:

  • (ArgumentError) —

    If the URI does not have a query string.

  • (KeyError) —

    If the query string does not have a ‘token’ key.

  • (KeyError) —

    If the decoded token does not have a ‘url’ key.

  • (TypeError) —

    If the ‘url’ key is not a String.

  • (TypeError) —

    If the ‘url’ key is not a URI::HTTP.

  • Inherited from #decode.

Since:

  • 0.1.0



337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 337

def decode_uri(u)
  q = u.query
  if q.nil?
    raise ArgumentError, "Expected the URI to have a query string, but it did not"
  end

  f = URI.decode_www_form(q)

  c = f.assoc("token")
  if !c
    raise KeyError, "Expected the query string to have a 'token' key, but it did not"
  end

  t = c[1]

  d = decode(t)
  if !d.key?("url")
    raise KeyError, "Expected the decoded token to have a 'url' key, but it did not"
  end

  s = d["url"]
  if !s.is_a?(String)
    raise TypeError, "Expected the 'url' key to be a String, but it was a #{s.class}"
  end

  g = URI.parse(s)
  if !g.is_a?(URI::HTTP)
    raise TypeError, "Expected the 'url' key to be a URI::HTTP, but it was a #{g.class}"
  end

  g
end

#encode(p) ⇒ String

encode encodes a payload.

Examples:

token = jwt.encode(payload)

Parameters:

  • p (Hash{T.untyped => T.untyped}) —

    The payload to encode

Returns:

  • (String) —

    An encoded token.

Raises:

  • Inherited from JWT.encode of Ruby JWT.

Since:

  • 0.1.0



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 300

def encode(p)
  p = p.clone

  t = Time.now.utc.to_i

  for c in @claims
    if c.is_a?(ExpClaim) && c.ttl != 0
      p["exp"] = t + c.ttl
      next
    end

    if c.is_a?(IatClaim)
      p["iat"] = t
      next
    end
  end

  JWT.encode(p, @secret, @algorithm)
end

#encode_body(p) ⇒ Hash{T.untyped => T.untyped}

encode_body encodes a payload by adding a token to the body. This method returns a shallow copy of the payload with the token added. It does not modify the original payload.

Examples:

req.body = jwt.encode_body(payload).to_json

Parameters:

  • p (Hash{T.untyped => T.untyped}) —

    The payload to encode.

Returns:

  • (Hash{T.untyped => T.untyped}) —

    An encoded body.

Raises:

Since:

  • 0.1.0



284
285
286
287
288
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 284

def encode_body(p)
  p = p.clone
  p["token"] = encode(p)
  p
end

#encode_header(p) ⇒ String

encode_header encodes a payload by adding a token to the header.

Examples:

req["Authorization"] = "Bearer #{jwt.encode_header(payload)}"

Parameters:

  • p (T.untyped) —

    The payload to encode.

Returns:

  • (String) —

    An encoded header.

Raises:

Since:

  • 0.1.0



268
269
270
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 268

def encode_header(p)
  encode({"payload" => p})
end

#encode_uri(u) ⇒ URI::HTTP

encode_uri encodes a URI by adding a token to the query string. This method returns a shallow copy of the URI with the token added. It does not modify the original URI.

Examples:

uri = jwt.encode_uri(uri)

Parameters:

  • u (URI::HTTP) —

    The URI to encode.

Returns:

  • (URI::HTTP) —

    An encoded URI.

Raises:

Since:

  • 0.1.0



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/onlyoffice/docs_integration_sdk/jwt.rb', line 240

def encode_uri(u)
  u = u.clone

  q = u.query
  if q.nil?
    q = ""
  end

  f = URI.decode_www_form(q)

  t = encode({"url" => u.to_s})
  f.append(["token", t])

  u.query = URI.encode_www_form(f)

  u
end