1 -module(noregex). 2 -export([main/1]). 3 4 isalphanum(C) when C > 47, C < 58; C > 64, C < 91; C > 96, C < 123 -> true; 5 isalphanum(_) -> false. 6 7 %% Generate a temporary file name of length N 8 genname(0, L) -> L; 9 genname(N, L) -> 10 R = random:uniform(123), 11 case isalphanum(R) of 12 true -> genname(N-1, [R|L]); 13 false -> genname(N, L) 14 end. 15 16 %% Returns a randomly generated temporary file path where the basename is 17 %% of length N 18 mktemppath(Prefix, N) -> Prefix ++ "/" ++ genname(N, []). 19 20 %% Removes passwords embedded in URLs from a log file. 21 scrub_file(Tmpdir, F) -> 22 %% make a temporary directory if it does not exist yet. 23 case file:make_dir(Tmpdir) of 24 ok -> ok; 25 {error,eexist} -> ok; 26 _ -> exit({error, failed_to_make_tmpdir}) 27 end, 28 29 %% Move the original file out of the way. 30 T = mktemppath(Tmpdir, 16), 31 case file:rename(F, T) of 32 ok -> ok; 33 _ -> exit({error, failed_to_move_file}) 34 end, 35 36 %% Now open it for reading. 37 {_, In} = file:open([T], read), 38 %% Open the original path for writing. 39 {_, Out} = file:open([F], write), 40 41 %% Call the function that will scrub the lines. 42 scrub_lines(In, Out), 43 44 %% Close the file handles and return the path to the original file. 45 file:close(Out), 46 file:close(In), 47 T. 48 49 %% This is where the log file is actually read linewise and where 50 %% the scrubbing function is invoked for lines that contain URLs. 51 scrub_lines(In, Out) -> 52 L = io:get_line(In, ''), 53 case L of 54 eof -> ok; 55 _ -> 56 %% Does the line contain URLs? 57 case string:str(L, "://") of 58 0 -> io:format(Out, "~s", [L]); 59 _ -> S = scrub(split(L), 0, []), 60 io:format(Out, "~s", [S]) 61 end, 62 %% Continue with next line. 63 scrub_lines(In, Out) 64 end. 65 66 %% This function operates on a list of strings where each string with an 67 %% odd index was originally on the right hand side of a "://" token. 68 %% It is these odd numbered strings that need to be checked for embedded 69 %% authentication credentials. 70 scrub([], _, R) -> string_join("://", lists:reverse(R)); 71 scrub([H|T], Idx, R) -> 72 case (Idx rem 2) of 73 %% This is a string that was originally to left of a "://" token, 74 %% no need to sanitize. 75 0 -> scrub(T, Idx+1, [H|R]); 76 %% This string was originally to right of a "://" token, sanitize! 77 1 -> scrub(T, Idx+1, [scrub_token(H)|R]) 78 end. 79 80 %% Remove an embedded "user:password@" sequence in the string passed. 81 scrub_token(Text) -> 82 Pos = string:chr(Text, $@), 83 case Pos of 84 0 -> Text; 85 _ -> string:right(Text, string:len(Text)-Pos) 86 end. 87 88 %% Split lines that contain URLs into strings ("://" is the delimiter). 89 split(L) -> splitline(L, []). 90 91 splitline(Text, R) -> 92 Pos = string:str(Text, "://"), 93 %% Does the text contain the "://" token? 94 case Pos of 95 0 -> lists:reverse([Text|R]); %% no 96 _ -> 97 %% "://" token found, add the left hand side text to the result 98 %% accumulator and continue tokenizing the text to the right. 99 Left = string:left(Text, Pos-1), 100 Right = string:right(Text, string:len(Text)-Pos-2), 101 splitline(Right, [Left|R]) 102 end. 103 104 %% Borrowed from http://www.trapexit.org/String_join_with %%%%%%%%%%%%%% 105 %% Thanks folks! 106 string_join(Join, L) -> 107 string_join(Join, L, fun(E) -> E end). 108 109 string_join(_Join, L=[], _Conv) -> 110 L; 111 string_join(Join, [H|Q], Conv) -> 112 lists:flatten(lists:concat( 113 [Conv(H)|lists:map(fun(E) -> [Join, Conv(E)] end, Q)] 114 )). 115 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 116 117 %% Main function. 118 main([A]) -> 119 {A1,A2,A3} = now(), 120 random:seed(A1, A2, A3), 121 122 %% A single argument (the name of the file to be scrubbed) is expected. 123 F = atom_to_list(A), 124 T = scrub_file("tmp", F), 125 126 %% The scrubbed file content will be written to a new file that's 127 %% in the place of the original file. Where was the latter moved to? 128 io:format("~s~n", [T]), 129 130 init:stop().