RideLogic.pm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. package RideLogic;
  2. use strict;
  3. use POSIX;
  4. require Exporter;
  5. use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS);
  6. $VERSION = "0.01";
  7. @ISA = qw(Exporter);
  8. #@EXPORT = qw( daemonize
  9. # read_config
  10. # strip_whitespace
  11. # try
  12. # catch );
  13. #@EXPORT_OK = qw( daemonize
  14. # read_config
  15. # strip_whitespace
  16. # try
  17. # catch );
  18. #%EXPORT_TAGS = ( DEFAULT => [qw( &daemonize
  19. # &read_config
  20. # &strip_whitespace
  21. # &try
  22. # &catch )] );
  23. @EXPORT = qw( audit_user_card_start
  24. audit_user_card_end
  25. audit_user_pass_start
  26. audit_user_pass_end
  27. audit_users_start
  28. audit_users_end
  29. audit_admins_start
  30. audit_admins_end
  31. daemonize
  32. read_config
  33. strip_whitespace
  34. try
  35. catch );
  36. @EXPORT_OK = qw( audit_user_card_start
  37. audit_user_card_end
  38. audit_user_pass_start
  39. audit_user_pass_end
  40. audit_users_start
  41. audit_users_end
  42. audit_admins_start
  43. audit_admins_end
  44. daemonize
  45. read_config
  46. strip_whitespace
  47. try
  48. catch );
  49. %EXPORT_TAGS = ( DEFAULT => [qw( &audit_user_card_start
  50. &audit_user_card_end
  51. &audit_user_pass_start
  52. &audit_user_pass_end
  53. &audit_users_start
  54. &audit_users_end
  55. &audit_admins_start
  56. &audit_admins_end
  57. &daemonize
  58. &read_config
  59. &strip_whitespace
  60. &try
  61. &catch )] );
  62. our @ISA = qw(Exporter);
  63. our $VERSION="0.1";
  64. #our $RIDELOGIC_DAEMON_CONF="/etc/ridelogic/daemon.conf";
  65. #our $RIDELOGIC_DAEMON_LOG_DIR="/var/log/ridelogic";
  66. #our $RIDELOGIC_DAEMON_PID_DIR="/var/run/ridelogic";
  67. #
  68. #our $RIDELOGIC_API_CONF="/etc/ridelogic/api.conf";
  69. our $RIDELOGIC_DAEMON_CONF="daemon.conf";
  70. our $RIDELOGIC_DAEMON_LOG_DIR="./";
  71. our $RIDELOGIC_DAEMON_PID_DIR="./";
  72. our $RIDELOGIC_API_CONF="api.conf";
  73. our $RIDELOGIC_IS_SQLITE=1;
  74. sub audit_user_pass_start {
  75. my $dbh = shift;
  76. my $pass_id = shift;
  77. my $comment = shift;
  78. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  79. if ($isSqlite) { return -1; }
  80. my @field = qw( user_pass_id logical_card_id issued activated firstused lastused nrides_orig nrides_remain nday_orig nday_expiration active rule queue_order comment expired paytype deactivated );
  81. my $ins_query = " insert into audit_user_pass ( timestamp, comment, old_" . $field[0];
  82. my $tail_ins_query = " select " . ($isSqlite ? "datetime('now', 'localtime')" : "now()") . ", ?, " . ($pass_id ? $field[0] : "null");
  83. for (my $i=1; $i<scalar(@field); $i++) {
  84. $ins_query .= ", old_" . $field[$i];
  85. $tail_ins_query .= ", " . ($pass_id ? $field[$i] : "null" );
  86. }
  87. $ins_query .= ") ";
  88. $tail_ins_query .= ($pass_id ? " from user_pass where user_pass_id = ?" : "");
  89. $ins_query .= $tail_ins_query;
  90. my $query = $dbh->prepare($ins_query);
  91. my $response = ($pass_id ? $query->execute($comment, $pass_id) : $query->execute($comment));
  92. return ($dbh->last_insert_id(undef, undef, undef, undef));
  93. }
  94. sub audit_user_pass_end {
  95. my $dbh = shift;
  96. my $pass_id = shift;
  97. my $audit_id = shift;
  98. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  99. if ($isSqlite) { return; }
  100. my @field = qw( user_pass_id logical_card_id issued activated firstused lastused nrides_orig nrides_remain nday_orig nday_expiration active rule queue_order comment expired paytype deactivated );
  101. my $up_query = " update audit_user_pass, user_pass set audit_user_pass.new_" . $field[0] . " = user_pass." . $field[0];
  102. for (my $i=1; $i<scalar(@field); $i++) {
  103. $up_query .= ", audit_user_pass.new_".$field[$i] . " = user_pass." . $field[$i];
  104. }
  105. $up_query .= " where audit_user_pass.audit_user_pass_id = ? and user_pass.user_pass_id = ? ";
  106. my $query = $dbh->prepare($up_query);
  107. my $response = $query->execute($audit_id, $pass_id);
  108. }
  109. sub audit_user_card_start {
  110. my $dbh = shift;
  111. my $card_id = shift;
  112. my $comment = shift;
  113. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  114. if ($isSqlite) { return -1; }
  115. my @field = qw( logical_card_id mag_token rfid_token comment lastused userid issued firstused group_id active deactivated issuetype );
  116. my $ins_query = " insert into audit_user_card ( timestamp, comment, old_" . $field[0];
  117. my $tail_ins_query = " select " . ($isSqlite ? "datetime('now', 'localtime')" : "now()") . ", ?, " . ($card_id ? $field[0] : "null");
  118. for (my $i=1; $i<scalar(@field); $i++) {
  119. $ins_query .= ", old_" . $field[$i];
  120. $tail_ins_query .= ", " . ($card_id ? $field[$i] : "null");
  121. }
  122. $ins_query .= ") ";
  123. $tail_ins_query .= ($card_id ? " from user_card where logical_card_id = ?" : "");
  124. $ins_query .= $tail_ins_query;
  125. my $query = $dbh->prepare($ins_query);
  126. my $response = ($card_id ? $query->execute($comment, $card_id) : $query->execute($comment) );
  127. return ($dbh->last_insert_id(undef, undef, undef, undef));
  128. }
  129. sub audit_user_card_end {
  130. my $dbh = shift;
  131. my $card_id = shift;
  132. my $audit_id = shift;
  133. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  134. if ($isSqlite) { return; }
  135. my @field = qw( logical_card_id mag_token rfid_token comment lastused userid issued firstused group_id active deactivated issuetype );
  136. my $up_query = " update audit_user_card, user_card set audit_user_card.new_" . $field[0] . " = user_card." . $field[0];
  137. for (my $i=1; $i<scalar(@field); $i++) {
  138. $up_query .= ", audit_user_card.new_".$field[$i] . " = user_card." . $field[$i];
  139. }
  140. $up_query .= " where audit_user_card.audit_user_card_id = ? and user_card.logical_card_id = ? ";
  141. my $query = $dbh->prepare($up_query);
  142. my $response = $query->execute($audit_id, $card_id);
  143. }
  144. sub audit_users_start {
  145. my $dbh = shift;
  146. my $userid = shift;
  147. my $comment = shift;
  148. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  149. if ($isSqlite) { return -1; }
  150. my @field = qw( username passwordhash userid comment first_name last_name phone email address city state zip created active
  151. shipping_address shipping_city shipping_state shipping_zip shipping_name shipping_country_code shipping_country_name reset_attempts );
  152. my $ins_query = " insert into audit_users ( timestamp, comment, old_" . $field[0];
  153. my $tail_ins_query = " select " . ($isSqlite ? "datetime('now', 'localtime')" : "now()") . ", ?, " . ($userid ? $field[0] : "null");
  154. for (my $i=1; $i<scalar(@field); $i++) {
  155. $ins_query .= ", old_".$field[$i];
  156. $tail_ins_query .= ", " . ($userid ? $field[$i] : "null");
  157. }
  158. $ins_query .= ") ";
  159. $tail_ins_query .= ($userid ? " from users where userid = ?" : "");
  160. $ins_query .= $tail_ins_query;
  161. my $query = $dbh->prepare($ins_query);
  162. my $response = ($userid ? $query->execute($comment, $userid) : $query->execute($comment) );
  163. return ($dbh->last_insert_id(undef, undef, undef, undef));
  164. }
  165. sub audit_users_end {
  166. my $dbh = shift;
  167. my $userid = shift;
  168. my $audit_id = shift;
  169. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  170. if ($isSqlite) { return; }
  171. my @field = qw( username passwordhash userid comment first_name last_name phone email address city state zip created active
  172. shipping_address shipping_city shipping_state shipping_zip shipping_name shipping_country_code shipping_country_name reset_attempts );
  173. my $up_query = " update audit_users, users set audit_users.new_" . $field[0] . " = users." . $field[0];
  174. for (my $i=1; $i<scalar(@field); $i++) {
  175. $up_query .= ", audit_users.new_".$field[$i] . " = users." . $field[$i];
  176. }
  177. $up_query .= " where audit_users.audit_users_id = ? and users.userid = ? ";
  178. my $query = $dbh->prepare($up_query);
  179. my $response = $query->execute($audit_id, $userid);
  180. }
  181. sub audit_admins_start {
  182. my $dbh = shift;
  183. my $userid = shift;
  184. my $comment = shift;
  185. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  186. if ($isSqlite) { return -1; }
  187. my @field = qw( username password userid );
  188. my $ins_query = " insert into audit_admins ( timestamp, comment, old_" . $field[0];
  189. my $tail_ins_query = " select " . ($isSqlite ? "datetime('now', 'localtime')" : "now()") . ", ?, " . ($userid ? $field[0] : "null");
  190. for (my $i=1; $i<scalar(@field); $i++) {
  191. $ins_query .= ", old_".$field[$i];
  192. $tail_ins_query .= ", " . ($userid ? $field[$i] : "null");
  193. }
  194. $ins_query .= ") ";
  195. $tail_ins_query .= ($userid ? " from admins where userid = ?" : "");
  196. $ins_query .= $tail_ins_query;
  197. my $query = $dbh->prepare($ins_query);
  198. my $response = ($userid ? $query->execute($comment, $userid) : $query->execute($comment) );
  199. return ($dbh->last_insert_id(undef, undef, undef, undef));
  200. }
  201. sub audit_admins_end {
  202. my $dbh = shift;
  203. my $userid = shift;
  204. my $audit_id = shift;
  205. my $isSqlite = $RIDELOGIC_IS_SQLITE;
  206. if ($isSqlite) { return; }
  207. my @field = qw( username password userid );
  208. my $up_query = " update audit_admins, admins set audit_admins.new_" . $field[0] . " = admins." . $field[0];
  209. for (my $i=1; $i<scalar(@field); $i++) {
  210. $up_query .= ", audit_admins.new_".$field[$i] . " = admins." . $field[$i];
  211. }
  212. $up_query .= " where audit_admins.audit_admins_id = ? and admins.userid = ? ";
  213. my $query = $dbh->prepare($up_query);
  214. my $response = $query->execute($audit_id, $userid);
  215. }
  216. #----------------------------------------------Ugly exception handling logic using closures and anonymous functions----
  217. #-------------------------------------------This is in there to deal with the fact that CreditCall uses the die("error")
  218. #-------------------------------------------function instead of returning an error message in many cases...
  219. # This utility function returns the passed string sans any leading or trailing whitespace.
  220. #
  221. sub strip_whitespace
  222. {
  223. my $str = shift; #grab our first parameter
  224. $str =~ s/^\s+//; #strip leading whitespace
  225. $str =~ s/\s+$//; #strip trailing whitespace
  226. return $str; #return the improved string
  227. }
  228. # This function takes two coderef parameters, the second of which is usually an explicit call to the
  229. # 'catch' function which itself takes a coderef parameter. This allows the code employing this suite of
  230. # functions to look somewhat like a conventional exception handling mechanism:
  231. #
  232. # try
  233. # {
  234. # do_something_that_might_die();
  235. # }
  236. # catch
  237. # {
  238. # my $errmsg = $_;
  239. # log_the_error_message($errmsg);
  240. # perform_some_cleanup();
  241. # };
  242. #
  243. # DO NOT FORGET THAT LAST SEMICOLON, EVERYTHING GOES TO HELL IF YOU DO!
  244. #
  245. sub try(&$)
  246. {
  247. my ($attempt, $handler) = @_;
  248. eval
  249. {
  250. &$attempt;
  251. };
  252. if($@)
  253. {
  254. do_catch($handler);
  255. }
  256. }
  257. # This function strips off the whitespace from the exception message reported by die()
  258. # and places the result into the default variable such that the code in the catch block can
  259. # just examine $_ to figure out what the cause of the error is, or to display or log
  260. # the error message.
  261. #
  262. sub do_catch(&$)
  263. {
  264. my ($handler) = @_;
  265. local $_ = strip_whitespace($@);
  266. &$handler;
  267. }
  268. # This just takes an explicit coderef and returns it unharmed. The only
  269. # purpose of this is so the try/catch structure looks pretty and familiar.
  270. #
  271. sub catch(&) {$_[0]}
  272. sub read_config
  273. {
  274. my $cfg_file = shift;
  275. my $cfg_href = shift;
  276. try
  277. {
  278. open my $fh, "$cfg_file";
  279. while (<$fh>) {
  280. next if /^#/;
  281. chomp;
  282. s/^\s+//;
  283. s/\s+$//;
  284. next if !$_;
  285. my ($var, $val) = split(/=/, $_);
  286. $cfg_href->{$var} = $val;
  287. }
  288. close $fh;
  289. }
  290. catch
  291. {
  292. my $errmsg = $_;
  293. die "Error processing config file $cfg_file, '$errmsg'. exiting\n";
  294. };
  295. }
  296. sub daemonize
  297. {
  298. my $logfile = shift;
  299. my $pidfile = shift;
  300. my ($untainted_lf, $untainted_pf);
  301. $untainted_lf = $1 if ($logfile =~ /^([^\0]+)$/);
  302. $untainted_pf = $1 if ($pidfile =~ /^([^\0]+)$/);
  303. try
  304. {
  305. chdir '/';
  306. umask 0;
  307. open STDIN, '/dev/null';
  308. open STDOUT, '/dev/null';
  309. open STDERR, '/dev/null';
  310. my $pid = fork;
  311. exit if $pid;
  312. setsid;
  313. if ($untainted_lf)
  314. {
  315. close STDOUT;
  316. close STDERR;
  317. sysopen( STDOUT, $untainted_lf, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
  318. sysopen( STDERR, $untainted_lf, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
  319. }
  320. if ($untainted_pf)
  321. {
  322. sysopen( my $fh, $untainted_pf, O_WRONLY|O_APPEND|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH );
  323. #open my $fh, ">$untainted_pf";
  324. print $fh $$, "\n";
  325. close $fh ;
  326. }
  327. }
  328. catch
  329. {
  330. my $errmsg = $_;
  331. die "Failed to daemonize: '$errmsg', exiting\n";
  332. };
  333. }
  334. return 1;