Odyssey
User.php
1 <?php
2  /**
3  * Model containing user login information
4  */
5  require_once('hcuCommon.i');
6 
7  class User {
8  //constants
9  const MEM_UNUSED = 0; // Flag Unused
10  const MEM_FORCE_RESET = 2; // Force Reset by Admin
11  const MEM_LOGIN_FAILED_EMAIL = 4; // Login Failed -- Email Incorrect
12  const MEM_LOGIN_FAILED_QST = 8; // Login Failed -- Challenge Questions
13  const MEM_LOGIN_FAILED_PWD = 16; // Login Failed -- Password Incorrect
14  const MEM_ASKBPAY = 32; // Flag Member for Bill Pay email
15  const MEM_LOGIN_FAILED_ALIAS = 64; // Login Failed -- Cannot use account # when alias is set
16  const MEM_LOGIN_FAILED_SAC = 128; // Login Failed -- Secure Access Code incorrect
17  const MEM_LOGIN_FAILED_BNDL = 256; // APP Login Failed -- MFABUNDLE missing or invalid
18  const MEM_LOGIN_FAILED_BNDL_TIMEOUT = 512; // APP Login Failed -- APP login process took too long
19  const MSGTX_TRANSFER = 1; // Transfer
20  const MSGTX_ES = 2; // Estatement
21  const MSGTX_WEBCONNECT = 4; // WebConnect
22  const MSGTX_TMP_SURVEY = 8; // temporary (session-long) flag for SurveyPopup SURVEY
23  const MSGTX_TMP_XAC_RQ = 16; // temporary (session-long) flag to indicate when an XAC packet has been requested
24  const MSGTX_TMP_XAX_LD = 32; // temporary (session-long) flag to indicate when an XAC packet has been successfully loaded
25  const MSGTX_INTUITUPD = 64; // IntuitUpdate message
26  const MSGTX_TXNDOWN = 128; // TxnDownload
27  const MSGTX_TMP_MKT = 256; // temporary (session-long) flag for SurveyPopup MESSAGE
28  const MSGTX_FORCE_EM = 512; // 'Force Email Change': when set the member will be prompted for email at login.
29  const MSGTX_PASSCHG = 1024; // Passchange
30  const MSGTX_ONLINEDISC = 2048; // Online Deposits disclosure acceptance - used in OnLineDeposits,
31  const MSGTX_PROMOHIDE = 4096; // Promo don't show me again
32  const MSGTX_STICKY = 8192; // "Sticky" Promo -- member can't suppress
33  const HCUTEMP_FLAGS = 49464; // The sum of all session long flags
34 
35  private $username;
36  private $creditUnion;
37  private $userRepo;
38  public $data = [];
39  private $dirtyFields = [];
40 
41  private $allowedProperties = [
42  'confidence',
43  'cuuser_group_id',
44  'email',
45  'failedremain',
46  'fchange',
47  'flog',
48  'fremain',
49  'llog',
50  'mfaquest',
51  'msg_tx',
52  'passwd',
53  'pchange',
54  'primary_account',
55  'savecqid',
56  'user_id',
57  'user_name',
58  'userflags',
59  ];
60  private $derivedProperties = [
61  'freset',
62  ];
63  public $isUserLoaded = false;
64 
65  /**
66  * User constructor.
67  * @param string $username
68  * @param String $cu
69  * @param UserRepo $userRepo
70  */
71  public function __construct(string $username, string $creditUnion, UserRepo $userRepo) {
72  if (!strlen($username) || preg_match("/[\\\`,\"\s;]/", $username)) {
73  throw new Exception(static::class . ": invalid username [$username]");
74  }
75 
76  if (!strlen($creditUnion)) {
77  throw new Exception(static::class . ": invalid credit union [$cu]");
78  }
79 
80  if (!$userRepo instanceof UserRepo) {
81  throw new Exception(static::class . ": need instance of UserRepo");
82  }
83  $this->username = $username;
84  $this->creditUnion = $creditUnion;
85  $this->userRepo = $userRepo;
86  $this->Load();
87  }
88 
89  /**
90  * Magic method returns allowed properties
91  * @param string $propertyName
92  * @return mixed|null
93  *
94  * @throws Exception
95  */
96  public function __get(string $propertyName) {
97  if (in_array($propertyName, array_merge($this->allowedProperties, $this->derivedProperties))) {
98  return $this->data[$propertyName] ?? null;
99  } else {
100  throw new Exception(static::class . ": Property [$propertyName] does not exist.");
101  }
102  }
103 
104  /**
105  * Magic method sets allowed properties
106  *
107  * @param string $propertyName
108  * @param string $value
109  *
110  * @throws Exception
111  */
112  public function __set(string $propertyName, string $value) {
113  if (in_array($propertyName, array_merge($this->allowedProperties))) {
114  $this->data[$propertyName] = $value;
115  $this->dirtyFields[] = $propertyName;
116  } else {
117  throw new Exception(static::class . ": Property [$propertyName] does not exist.");
118  }
119  }
120 
121  /**
122  * Magic method to check for existence of a property. Needed for functions like 'empty'
123  *
124  * @param String $propertyName
125  *
126  * @return bool
127  */
128  public function __isset(String $propertyName) {
129  return !empty($this->data[$propertyName]);
130  }
131 
132  /**
133  * Load the user model with data
134  *
135  * @throws Exception
136  */
137  private function Load() {
138  $this->data = $this->userRepo->Read($this->username);
139 
140  if (!$this->data) {
141  throw new Exception(static::class . ": Invalid user '$this->username' for credit union {$this->creditUnion}.");
142  }
143  $this->isUserLoaded = true;
144  // Derive further user properties
145  $this->data['mfaquest'] = $this->DecodeMFAJson(HCU_JsonDecode($this->data['mfaquest']));
146  $this->data['freset'] = $this->userflags & static::MEM_FORCE_RESET;
147  }
148 
149  /**
150  * Convert MFA data into a assoc array with this schema. This structure includes both challenge answer and secure code data.
151  * [
152  * mfacount: Number of challenge answers
153  * answers: Assoc array of question ids and answers
154  * challenge: Active challenge question id. Does not seem to be used anymore
155  * authcode: Active secure access code
156  * authexpires: Active Secure access code expiration
157  * mfadate: Challenge answers save timestamp
158  * ]
159  *
160  * @param array $mfaJson Array of challenge questions from database
161  * @return array
162  */
163  private function DecodeMFAJson(array $mfaJson) {
164  return [
165  'mfacount' => HCU_array_key_exists('answers', $mfaJson) ? count($mfaJson['answers']) : 0,
166  'answers' => HCU_array_key_exists('answers', $mfaJson) ?? [],
167  'challenge' => HCU_array_key_exists('challenge', $mfaJson) ? intval($mfaJson['challenge']) : 0,
168  'authcode' => HCU_array_key_exists('authcode', $mfaJson) ? strtolower($mfaJson['authcode']) : null,
169  'authexpires' => HCU_array_key_exists('authexpires', $mfaJson) ? intval($mfaJson['authexpires']) : null,
170  'mfadate' => HCU_array_key_exists('mfadate', $mfaJson) ? intval($mfaJson['mfadate']) : 0,
171  ];
172  }
173 
174  private function GetAccounts() {
175  // get the possible account numbers
176  $sql = "SELECT DISTINCT ua.accountnumber
177  FROM {$cu}user u
178  INNER JOIN {$cu}useraccounts ua on ua.user_id = u.user_id
179  WHERE u.user_name ilike '{$this->user_name}'";
180 
181  $rs = db_query( $sql, $pHBEnv["dbh"] );
182  }
183 
184  }
__get(string $propertyName)
Definition: User.php:96
__set(string $propertyName, string $value)
Definition: User.php:112
__construct(string $username, string $creditUnion, UserRepo $userRepo)
Definition: User.php:71
Definition: User.php:7
Load()
Definition: User.php:137
DecodeMFAJson(array $mfaJson)
Definition: User.php:163
__isset(String $propertyName)
Definition: User.php:128