An easy point of sale system with automatic inventory tracking. https://netsyms.biz/apps/nickelbox/
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

User.lib.php 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. <?php
  2. /*
  3. * This Source Code Form is subject to the terms of the Mozilla Public
  4. * License, v. 2.0. If a copy of the MPL was not distributed with this
  5. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  6. */
  7. class User {
  8. private $uid = null;
  9. private $username;
  10. private $email;
  11. private $realname;
  12. private $has2fa = false;
  13. private $exists = false;
  14. public function __construct(int $uid, string $username = "") {
  15. // Check if user exists
  16. $client = new GuzzleHttp\Client();
  17. $response = $client
  18. ->request('POST', PORTAL_API, [
  19. 'form_params' => [
  20. 'key' => PORTAL_KEY,
  21. 'action' => "userexists",
  22. 'uid' => $uid
  23. ]
  24. ]);
  25. if ($response->getStatusCode() > 299) {
  26. sendError("Login server error: " . $response->getBody());
  27. }
  28. $resp = json_decode($response->getBody(), TRUE);
  29. if ($resp['status'] == "OK" && $resp['exists'] === true) {
  30. $this->exists = true;
  31. } else {
  32. $this->uid = $uid;
  33. $this->username = $username;
  34. $this->exists = false;
  35. }
  36. if ($this->exists) {
  37. // Get user info
  38. $client = new GuzzleHttp\Client();
  39. $response = $client
  40. ->request('POST', PORTAL_API, [
  41. 'form_params' => [
  42. 'key' => PORTAL_KEY,
  43. 'action' => "userinfo",
  44. 'uid' => $uid
  45. ]
  46. ]);
  47. if ($response->getStatusCode() > 299) {
  48. sendError("Login server error: " . $response->getBody());
  49. }
  50. $resp = json_decode($response->getBody(), TRUE);
  51. if ($resp['status'] == "OK") {
  52. $this->uid = $resp['data']['uid'] * 1;
  53. $this->username = $resp['data']['username'];
  54. $this->email = $resp['data']['email'];
  55. $this->realname = $resp['data']['name'];
  56. } else {
  57. sendError("Login server error: " . $resp['msg']);
  58. }
  59. }
  60. }
  61. public static function byUsername(string $username): User {
  62. $client = new GuzzleHttp\Client();
  63. $response = $client
  64. ->request('POST', PORTAL_API, [
  65. 'form_params' => [
  66. 'key' => PORTAL_KEY,
  67. 'username' => $username,
  68. 'action' => "userinfo"
  69. ]
  70. ]);
  71. if ($response->getStatusCode() > 299) {
  72. sendError("Login server error: " . $response->getBody());
  73. }
  74. $resp = json_decode($response->getBody(), TRUE);
  75. if (!isset($resp['status'])) {
  76. sendError("Login server error: " . $resp);
  77. }
  78. if ($resp['status'] == "OK") {
  79. return new self($resp['data']['uid'] * 1);
  80. } else {
  81. return new self(-1, $username);
  82. }
  83. }
  84. public function exists(): bool {
  85. return $this->exists;
  86. }
  87. public function has2fa(): bool {
  88. if (!$this->exists) {
  89. return false;
  90. }
  91. $client = new GuzzleHttp\Client();
  92. $response = $client
  93. ->request('POST', PORTAL_API, [
  94. 'form_params' => [
  95. 'key' => PORTAL_KEY,
  96. 'action' => "hastotp",
  97. 'username' => $this->username
  98. ]
  99. ]);
  100. if ($response->getStatusCode() > 299) {
  101. sendError("Login server error: " . $response->getBody());
  102. }
  103. $resp = json_decode($response->getBody(), TRUE);
  104. if ($resp['status'] == "OK") {
  105. return $resp['otp'] == true;
  106. } else {
  107. return false;
  108. }
  109. }
  110. function getUsername() {
  111. return $this->username;
  112. }
  113. function getUID() {
  114. return $this->uid;
  115. }
  116. function getEmail() {
  117. return $this->email;
  118. }
  119. function getName() {
  120. return $this->realname;
  121. }
  122. /**
  123. * Check the given plaintext password against the stored hash.
  124. * @param string $password
  125. * @return bool
  126. */
  127. function checkPassword(string $password): bool {
  128. $client = new GuzzleHttp\Client();
  129. $response = $client
  130. ->request('POST', PORTAL_API, [
  131. 'form_params' => [
  132. 'key' => PORTAL_KEY,
  133. 'action' => "auth",
  134. 'username' => $this->username,
  135. 'password' => $password
  136. ]
  137. ]);
  138. if ($response->getStatusCode() > 299) {
  139. sendError("Login server error: " . $response->getBody());
  140. }
  141. $resp = json_decode($response->getBody(), TRUE);
  142. if ($resp['status'] == "OK") {
  143. return true;
  144. } else {
  145. return false;
  146. }
  147. }
  148. function check2fa(string $code): bool {
  149. if (!$this->has2fa) {
  150. return true;
  151. }
  152. $client = new GuzzleHttp\Client();
  153. $response = $client
  154. ->request('POST', PORTAL_API, [
  155. 'form_params' => [
  156. 'key' => PORTAL_KEY,
  157. 'action' => "verifytotp",
  158. 'username' => $this->username,
  159. 'code' => $code
  160. ]
  161. ]);
  162. if ($response->getStatusCode() > 299) {
  163. sendError("Login server error: " . $response->getBody());
  164. }
  165. $resp = json_decode($response->getBody(), TRUE);
  166. if ($resp['status'] == "OK") {
  167. return $resp['valid'];
  168. } else {
  169. return false;
  170. }
  171. }
  172. /**
  173. * Check if the given username has the given permission (or admin access)
  174. * @global $database $database
  175. * @param string $code
  176. * @return boolean TRUE if the user has the permission (or admin access), else FALSE
  177. */
  178. function hasPermission(string $code): bool {
  179. $client = new GuzzleHttp\Client();
  180. $response = $client
  181. ->request('POST', PORTAL_API, [
  182. 'form_params' => [
  183. 'key' => PORTAL_KEY,
  184. 'action' => "permission",
  185. 'username' => $this->username,
  186. 'code' => $code
  187. ]
  188. ]);
  189. if ($response->getStatusCode() > 299) {
  190. sendError("Login server error: " . $response->getBody());
  191. }
  192. $resp = json_decode($response->getBody(), TRUE);
  193. if ($resp['status'] == "OK") {
  194. return $resp['has_permission'];
  195. } else {
  196. return false;
  197. }
  198. }
  199. /**
  200. * Get the account status.
  201. * @return \AccountStatus
  202. */
  203. function getStatus(): AccountStatus {
  204. $client = new GuzzleHttp\Client();
  205. $response = $client
  206. ->request('POST', PORTAL_API, [
  207. 'form_params' => [
  208. 'key' => PORTAL_KEY,
  209. 'action' => "acctstatus",
  210. 'username' => $this->username
  211. ]
  212. ]);
  213. if ($response->getStatusCode() > 299) {
  214. sendError("Login server error: " . $response->getBody());
  215. }
  216. $resp = json_decode($response->getBody(), TRUE);
  217. if ($resp['status'] == "OK") {
  218. return AccountStatus::fromString($resp['account']);
  219. } else {
  220. return null;
  221. }
  222. }
  223. function sendAlertEmail(string $appname = SITE_TITLE) {
  224. $client = new GuzzleHttp\Client();
  225. $response = $client
  226. ->request('POST', PORTAL_API, [
  227. 'form_params' => [
  228. 'key' => PORTAL_KEY,
  229. 'action' => "alertemail",
  230. 'username' => $this->username,
  231. 'appname' => SITE_TITLE
  232. ]
  233. ]);
  234. if ($response->getStatusCode() > 299) {
  235. return "An unknown error occurred.";
  236. }
  237. $resp = json_decode($response->getBody(), TRUE);
  238. if ($resp['status'] == "OK") {
  239. return true;
  240. } else {
  241. return $resp['msg'];
  242. }
  243. }
  244. }
  245. class AccountStatus {
  246. const NORMAL = 1;
  247. const LOCKED_OR_DISABLED = 2;
  248. const CHANGE_PASSWORD = 3;
  249. const TERMINATED = 4;
  250. const ALERT_ON_ACCESS = 5;
  251. private $status;
  252. public function __construct(int $status) {
  253. $this->status = $status;
  254. }
  255. public static function fromString(string $status): AccountStatus {
  256. switch ($status) {
  257. case "NORMAL":
  258. return new self(self::NORMAL);
  259. case "LOCKED_OR_DISABLED":
  260. return new self(self::LOCKED_OR_DISABLED);
  261. case "CHANGE_PASSWORD":
  262. return new self(self::CHANGE_PASSWORD);
  263. case "TERMINATED":
  264. return new self(self::TERMINATED);
  265. case "ALERT_ON_ACCESS":
  266. return new self(self::ALERT_ON_ACCESS);
  267. default:
  268. return new self(0);
  269. }
  270. }
  271. /**
  272. * Get the account status/state as an integer.
  273. * @return int
  274. */
  275. public function get(): int {
  276. return $this->status;
  277. }
  278. /**
  279. * Get the account status/state as a string representation.
  280. * @return string
  281. */
  282. public function getString(): string {
  283. switch ($this->status) {
  284. case self::NORMAL:
  285. return "NORMAL";
  286. case self::LOCKED_OR_DISABLED:
  287. return "LOCKED_OR_DISABLED";
  288. case self::CHANGE_PASSWORD:
  289. return "CHANGE_PASSWORD";
  290. case self::TERMINATED:
  291. return "TERMINATED";
  292. case self::ALERT_ON_ACCESS:
  293. return "ALERT_ON_ACCESS";
  294. default:
  295. return "OTHER_" . $this->status;
  296. }
  297. }
  298. }