123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164(*
* Copyright (c) 2012 Anil Madhavapeddy <anil@recoil.org>
* Copyright (c) 2013 David Sheets <sheets@alum.mit.edu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*)openPrintfopenLwttypet={jar_path:string}exceptionInvalidNameofstringletinvalid_names=Re.(List.mapcompile[seq[bos;str"."];str"../";seq[bos;strFilename.dir_sep];seq[strFilename.dir_sep;eos];])letjar_path{jar_path}=jar_pathletfile_kind_matchpath~reg~dir~other=Lwt_unix.(statpath>>=fun{st_kind;_}->matchst_kindwith|S_REG->reg()|S_DIR->dir()|S_CHR|S_BLK|S_LNK|S_FIFO|S_SOCK->other())letrecmkdir_pdir=matchSys.file_existsdirwith|true->return()|false->mkdir_p(Filename.dirnamedir)>>=fun()->Lwt_unix.mkdirdir0o700letrecinit?jar_path()=letjar_path=matchjar_pathwith|None->lethome=trySys.getenv"HOME"withNot_found->"."inletbasedir=Filename.concathome".github"inFilename.concatbasedir"jar"|Somejar_path->jar_pathinmatchSys.file_existsjar_pathwith|true->return{jar_path}|false->printf"Github cookie jar: initialized %s\n"jar_path;mkdir_pjar_path>>=init~jar_path(* Save an authentication token to disk, under the [name]
* file in the jar *)letsave({jar_path}asjar)~name~auth=(ifList.exists(funre->Re.execprename)invalid_namesthenfail(InvalidNamename)elsereturn())>>=fun()->letrecbackup_path?(dirok=false)name=letfullname=Filename.concatjar_pathnameinletbackup()=letopenUnixinlettm=gmtime(gettimeofday())inletbackfname=sprintf"%s.%.4d%.2d%.2d.%2d%2d%2d.bak"name(1900+tm.tm_year)(1+tm.tm_mon)tm.tm_mdaytm.tm_hourtm.tm_mintm.tm_secinletfullback=Filename.concatjar_pathbackfnameinprintf"Github cookie jar: backing up\n%s -> %s\n"fullnamefullback;Lwt_unix.renamefullnamefullbackincatch(fun()->file_kind_matchfullname~reg:backup~dir:(ifdirokthenreturnelsebackup)~other:backup)(function|Unix.Unix_error(Unix.ENOENT,_,_)|Unix.Unix_error(Unix.ENOTDIR,_,_)->beginmatchFilename.dirnamenamewith|"."->return()|parent->backup_path~dirok:trueparentend|exn->failexn)inbackup_pathname>>=fun()->letfullname=Filename.concatjar_pathnameinmkdir_p(Filename.dirnamefullname)>>=fun()->letauth_fd=Unix.(openfilefullname[O_CREAT;O_TRUNC;O_WRONLY]0o600)inletauth_oc=Unix.out_channel_of_descrauth_fdinfprintfauth_oc"%s"(Github_j.string_of_authauth);close_outauth_oc;printf"Github cookie jar: created %s\n"fullname;returnjar(* Delete an authentication token from disk, given the [name] in the jar *)letdeletejar~name=ifList.exists(funre->Re.execprename)invalid_namesthenfail(InvalidNamename)elseLwt_unix.unlink(Filename.concatjar.jar_pathname)>>=fun()->returnjar(* Read a JSON auth file in and parse it *)letread_auth_file{jar_path}name=letfname=Filename.concatjar_pathnameinlet{Unix.st_perm;_}=Unix.statfnameinletsafe_perm=0o7770landst_perminbeginifsafe_perm<>st_permthenUnix.chmodfnamesafe_permend;Lwt_io.with_file~mode:Lwt_io.inputfname(funic->Lwt_stream.fold_s(funba->return(a^b))(Lwt_io.read_linesic)"">>=funbuf->return(Github_j.auth_of_stringbuf))(* Retrieve all the cookies *)letget_all({jar_path}asjar)=letrectraversedir=letbase=Filename.concatjar_pathdirinletfiles=Lwt_unix.files_of_directorybaseinLwt_stream.fold_s(funba->ifb="."||b=".."thenreturnaelsebeginletpath=Filename.concatbasebinletident=Filename.concatdirbinfile_kind_matchpath~reg:(fun()->read_auth_filejarident>>=funauth->return((ident,auth)::a))~dir:(fun()->traverseident>>=funsub->return(sub@a))~other:(fun()->returna)end)files[]intraverse""(* Get one cookie by name *)letgetjar~name=catch(fun()->read_auth_filejarname>>=funauth->return(Someauth))(fun_->return_none)