Class: FFI::OTR::UserState

Inherits:
Object
  • Object
show all
Includes:
FFI::OTR, Callbacks
Defined in:
lib/ffi/otr/user_state.rb

Overview

Wraps a OtrlUserState for convenient usage. Simply inherit from it, implement the Callbacks and pass your messages to #sending or #receiving.

Constant Summary collapse

DEFAULT_OPTS =
{
  policy: POLICY_DEFAULT,
  max_message_size: 1024,
  debug: false,
}

Constants included from FFI::OTR

INSTAG_BEST, INSTAG_MASTER, INSTAG_RECENT, INSTAG_RECENT_RECEIVED, INSTAG_RECENT_SENT, MIN_VALID_INSTAG, POLICY_ALLOW_V1, POLICY_ALLOW_V2, POLICY_ALLOW_V3, POLICY_ALWAYS, POLICY_DEFAULT, POLICY_ERROR_START_AKE, POLICY_MANUAL, POLICY_NEVER, POLICY_OPPORTUNISTIC, POLICY_REQUIRE_ENCRYPTION, POLICY_SEND_WHITESPACE_TAG, POLICY_VERSION_MASK, POLICY_WHITESPACE_START_AKE, VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Callbacks

#account_name, #account_name_free, #create_instag, #create_privkey, #display_otr_message, #gone_insecure, #gone_secure, #handle_msg_event, #handle_smp_event, #inject_message, #is_logged_in, #log_message, #max_message_size, #new_fingerprint, #notify, #otr_error_message, #otr_error_message_free, #policy, #protocol_name, #protocol_name_free, #received_symkey, #resent_msg_prefix, #resent_msg_prefix_free, #still_secure, #update_context_list, #write_fingerprints

Methods included from FFI::OTR

version

Constructor Details

#initialize(account, protocol, opts = {}) ⇒ UserState

Initialize OTR UserState.

If the :privkey option is set, load the key and implement the Callbacks#create_privkey callback to generate it.

If the :fingerprints options is set, load fingerprints and implement the Callbacks#new_fingerprint and Callbacks#write_fingerprints callbacks.

If the :instags option is set, load instance tags and implement the Callbacks#create_instag callback to generate it.

Note: There is a bug in OTR versions <= 4.1.1 that makes it mandatory to have a Callbacks#create_instag callback. So specify the file name or implement it yourself.

You can always override the callbacks, but if you don't specify those files, you must implement them yourself.

Options Hash (opts):

  • :privkey (String) — default: nil

    filename where the private key is stored

  • :fingerprints (String) — default: nil

    filename where fingerprints are stored

  • :instags (String) — default: nil

    filename where instance tags are stored

  • :policy (Fixnum) — default: POLICY_DEFAULT

    OTR policy

  • :max_message_size (Fixnum) — default: 1024

    Max message size

  • :debug (Boolean) — default: false

    Output debug messages for missing callbacks


41
42
43
44
45
46
47
48
49
# File 'lib/ffi/otr/user_state.rb', line 41

def initialize(, protocol, opts = {})
  @account, @protocol = , protocol
  @opts = DEFAULT_OPTS.merge(opts)
  @userstate = otrl_userstate_create
  otrl_privkey_read(@userstate, @opts[:privkey])  if @opts[:privkey]
  otrl_privkey_read_fingerprints(@userstate, @opts[:fingerprints], nil, nil)  if @opts[:fingerprints]
  otrl_instag_read(@userstate, @opts[:instags])  if @opts[:instags]
  setup_ui_ops
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Object (private)

Note:

This only works for methods that take the userstate as first argument.

You can call any otrl_* method without the otrl_*-prefix, and the userstate is passed in as the first argument. For example: userstate.privkey_write_fingerprints("fingerprints.otr")


125
126
127
128
# File 'lib/ffi/otr/user_state.rb', line 125

def method_missing(name, *args)
  n = "otrl_#{name}"
  respond_to?(n) ? send(n, @userstate, *args) : super(name, *args)
end

Instance Attribute Details

#accountObject (readonly)

Returns the value of attribute account


14
15
16
# File 'lib/ffi/otr/user_state.rb', line 14

def 
  @account
end

#optsObject (readonly)

Returns the value of attribute opts


14
15
16
# File 'lib/ffi/otr/user_state.rb', line 14

def opts
  @opts
end

#protocolObject (readonly)

Returns the value of attribute protocol


14
15
16
# File 'lib/ffi/otr/user_state.rb', line 14

def protocol
  @protocol
end

#ui_opsObject (readonly)

Returns the value of attribute ui_ops


14
15
16
# File 'lib/ffi/otr/user_state.rb', line 14

def ui_ops
  @ui_ops
end

#userstateObject (readonly)

Returns the value of attribute userstate


14
15
16
# File 'lib/ffi/otr/user_state.rb', line 14

def userstate
  @userstate
end

Instance Method Details

#fingerprintObject

Get the fingerprint of this userstates private key.


100
101
102
103
104
105
106
# File 'lib/ffi/otr/user_state.rb', line 100

def fingerprint
  fp = FFI::MemoryPointer.new(:buffer_out, 45)
  unless otrl_privkey_fingerprint(@userstate, fp, @account, "xmpp")
    raise "Error getting fingerprint."
  end
  fp.read_string
end

#receiving(user, message, opdata = nil) ⇒ String

Pass an incoming message through OTR.

Decrypts the message and tries to establish new session if necessary.


88
89
90
91
92
93
94
95
96
97
# File 'lib/ffi/otr/user_state.rb', line 88

def receiving(user, message, opdata = nil)
  new_msg = FFI::MemoryPointer.new(:pointer); new_msg.autorelease = false
  unless otrl_message_receiving(@userstate, @ui_ops, opdata,
      @account, @protocol, user, message, new_msg, nil, nil, nil, nil) == 0
    return # ignore internal messages
  end
  res = (p = new_msg.read_pointer) && !p.null? ? p.read_string : message
  otrl_message_free(new_msg)
  res
end

#sending(user, message, opdata = nil) ⇒ String

Pass an outgoing message through OTR.

If there is an active OTR session with this user, the message will be encrypted. Otherwise, the whitespace tag is appended, depending on the policy.


60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/ffi/otr/user_state.rb', line 60

def sending(user, message, opdata = nil)
  new_msg = FFI::MemoryPointer.new(:pointer); new_msg.autorelease = false
  unless otrl_message_sending(@userstate, @ui_ops, opdata,
                              @account, @protocol, user,
                              INSTAG_BEST, # instag
                              message,
                              nil, # tlvs
                              new_msg,
                              nil, # fragPolicy
                              nil, # contextp
                              nil, # add_appdata
                              nil # data
                             ) == 0
    raise "Error encrypting message. Do NOT send it."
  end
  res = (p = new_msg.read_pointer) && !p.null? ? p.read_string : message
  otrl_message_free(new_msg)
  res
end