diff options
author | Josias <me@josias.dev> | 2020-08-17 11:37:06 +0200 |
---|---|---|
committer | Josias <me@josias.dev> | 2020-08-17 11:37:06 +0200 |
commit | 8bd564f891c755c87e8d97001b296d713988de70 (patch) | |
tree | 2adeae42c1cfbbac871a1fbec7d8da7f0ccfdab0 |
This is a workable program but has bugs and cuts corners.
-rw-r--r-- | .gitmodules | 6 | ||||
-rw-r--r-- | build.zig | 22 | ||||
m--------- | lib/apple_pie | 0 | ||||
m--------- | lib/sqlite | 0 | ||||
-rw-r--r-- | src/main.zig | 131 | ||||
-rw-r--r-- | src/store.zig | 130 | ||||
-rw-r--r-- | ui/index.html | 16 | ||||
-rw-r--r-- | ui/script.js | 56 | ||||
-rw-r--r-- | ui/words.js | 501 |
9 files changed, 862 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..1d0b5a7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "lib/apple_pie"] + path = lib/apple_pie + url = https://github.com/Luukdegram/apple_pie.git +[submodule "lib/sqlite"] + path = lib/sqlite + url = https://github.com/leroycep/sqlite-zig diff --git a/build.zig b/build.zig new file mode 100644 index 0000000..d73521e --- /dev/null +++ b/build.zig @@ -0,0 +1,22 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + const target = b.standardTargetOptions(.{}); + + const mode = b.standardReleaseOptions(); + + const exe = b.addExecutable("accspy", "src/main.zig"); + exe.setTarget(target); + exe.setBuildMode(mode); + exe.addPackagePath("apple_pie", "lib/apple_pie/src/apple_pie.zig"); + //exe.addPackagePath("sqlite", "lib/sqlite/src/sqlite.zig"); + //exe.linkSystemLibrary("sqlite3"); + //exe.linkSystemLibrary("c"); + exe.install(); + + const run_cmd = exe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/lib/apple_pie b/lib/apple_pie new file mode 160000 +Subproject c49b8cc4f13bc1618b20f618c435f4411d82c10 diff --git a/lib/sqlite b/lib/sqlite new file mode 160000 +Subproject 28181e526281e3d19b8830bb0bebb8a19ca6cdd diff --git a/src/main.zig b/src/main.zig new file mode 100644 index 0000000..08ff23e --- /dev/null +++ b/src/main.zig @@ -0,0 +1,131 @@ +const std = @import("std"); +const mem = std.mem; +const json = std.json; +const allocator = std.heap.page_allocator; + +const http = @import("apple_pie"); +const file_server = http.file_server; + +const Error = error{ BadRequest, MissingInfo }; + +const store = @import("store.zig"); + +pub fn main() anyerror!void { + // try file_server.init("ui/", allocator); + // defer file_server.deinit(); + try http.server.listenAndServe( + allocator, + try std.net.Address.parseIp("127.0.0.1", 8080), + comptime Router(&[_]Route{ + // .{ + // .path = "/ui", + // .serveFn = file_server.serve, + //}, + .{ + .path = "/addurl", + .serveFn = addurl, + }, + .{ + .path = "/getlogs", + .serveFn = getlogs, + }, + }), + ); +} + +const AddUrlRequest = struct { + username: []u8, + title: []u8, + url: []u8, + timestamp: i64, +}; + +const GetLogsRequest = struct { + username: []u8, + from: i64, // TODO implement +}; + +// TODO respond with appropriate error codes instead of returning error +// removing Zig errors except for unrecoverable ones +fn addurl(response: *http.Response, request: http.Request) !void { + std.debug.print("Is this working?\n", .{}); + if (!mem.eql(u8, request.method, "POST")) { + try response.write("Try with POST"); + return; + } + + var parser = json.Parser.init(allocator, true); + defer parser.deinit(); + + var stream = json.TokenStream.init(request.body); + const parsedReq = try json.parse(AddUrlRequest, &stream, .{ .allocator = allocator }); + + const log = store.Log{ + .url = parsedReq.url, + .title = parsedReq.title, + .timestamp = parsedReq.timestamp, + }; + + var logger = try store.Logger.init(allocator, parsedReq.username); + + std.debug.print("Putting into database...\n", .{}); + + try logger.addURL(log); + + std.debug.print("Successfully logged {}\n", .{log}); + + try response.write("Success\n"); +} + +fn getlogs(response: *http.Response, request: http.Request) !void { + std.debug.print("What.\n", .{}); + if (!mem.eql(u8, request.method, "POST")) { + try response.write("Try with POST"); + return; + } + + //try response.headers.put("Access-Control-Allow-Origin", "*"); + //try response.headers.put("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); + //try response.headers.put("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept"); + + var parser = json.Parser.init(allocator, true); + defer parser.deinit(); + + var stream = json.TokenStream.init(request.body); + const parsedReq = try json.parse(GetLogsRequest, &stream, .{ .allocator = allocator }); + + var logger = try store.Logger.init(allocator, parsedReq.username); + + const logs = try logger.getLogs(); + var string = std.ArrayList(u8).init(allocator); + try json.stringify(logs, .{}, string.writer()); + + std.debug.print("Responding with: {}\n", .{string.items}); + try response.write(string.items); +} + +fn Router(comptime routes: []const Route) http.server.RequestHandler { + std.debug.assert(routes.len > 0); + + return struct { + fn serve(response: *http.Response, request: http.Request) callconv(.Async) !void { + inline for (routes) |route| { + if (std.mem.eql(u8, request.url.path, route.path)) { // TODO fix this terrible sin with a better router + return route.serveFn(response, request); + } + } + } + }.serve; +} + +const Route = struct { + path: []const u8, + serveFn: http.server.RequestHandler, + + fn init(path: []const u8, serveFn: http.server.RequestHandler) Route { + return Route{ + .path = path, + .serveFn = serveFn, + }; + } +}; diff --git a/src/store.zig b/src/store.zig new file mode 100644 index 0000000..9d3fc6f --- /dev/null +++ b/src/store.zig @@ -0,0 +1,130 @@ +const std = @import("std"); +const mem = std.mem; + +const default_allocator = std.heap.page_allocator; + +const logdir = "logs"; + +pub const Log = struct { + url: []const u8, + title: []const u8, + timestamp: i64, +}; + +/// gets and retrieves data from activity logs +/// TODO decide what to do when file is not found or contents are invalid +pub const Logger = struct { + user: []const u8, + path: []u8, + file: std.fs.File, + allocator: *std.mem.Allocator, + + pub fn init(allocator: *std.mem.Allocator, user: []const u8) !@This() { + var logfile = try std.fmt.allocPrint(allocator, "{}.csv", .{user}); + + var file = try std.fs.cwd().openFile(logfile[0..], .{ .write = true }); + + return @This(){ + .user = user, + .path = logfile, + .file = file, + .allocator = allocator, + }; + } + + /// adds a URL to the logs + pub fn addURL(self: @This(), log: Log) !void { + try self.file.seekTo(try self.file.getEndPos()); + + try self.file.writer().print("{},{},{}\n", .{ log.timestamp, log.title, log.url }); + } + + pub fn getLogs(self: @This()) ![]Log { + var logs = std.ArrayList(Log).init(self.allocator); + var lines = std.ArrayList(u8).init(self.allocator); + // ^ - to provide a combination of lines that is not deallocated, allowing slices to remain + + // read character by character to get line and then + // divide it by commas to determine each value + var line_num: usize = 0; + var line = std.ArrayList(u8).init(self.allocator); + var lines_i: usize = 0; + var part: u2 = 0; // can be 0, 1, or 2S + var chars: usize = 0; + try self.file.seekTo(0); + while (true) { + var char = self.file.reader().readByte() catch |_| break; + + switch (char) { + else => { + _ = try line.append(char); + }, + '\n' => { + var old_len = lines.items.len; + try lines.appendSlice(line.items); + var iter = mem.split(lines.items[old_len..], ","); + std.debug.print("Line: {}\n", .{lines.items[old_len..]}); + var timestamp = iter.next() orelse continue; + std.debug.print("Time: {}\n", .{try std.fmt.parseInt(i64, timestamp, 10)}); + var log = Log{ + .timestamp = try std.fmt.parseInt(i64, (timestamp), 10), + .title = iter.next() orelse continue, + .url = iter.next() orelse continue, + }; + try logs.append(log); + + chars += line.items.len + 1; + try self.file.seekTo(chars); + line_num += 1; + + line.deinit(); + line = std.ArrayList(u8).init(self.allocator); + }, + } + } + + return logs.items; + } + + /// returns all logs from a certain date + pub fn getFrom(self: @This(), logs: []Log, timestamp: i64) ![]Log { + var newLogs = std.ArrayList(Log).init(self.allocator); + for (logs) |log| { + if (log.timestamp >= timestamp) { + std.debug.print("Adding {}\n", .{log}); + try newLogs.append(log); + } + } + return newLogs.items; + } + + pub fn deinit(self: @This()) !void { + try self.file.close(); + } +}; + +test "add a URL" { + var logger = try Logger.init(default_allocator, "j"); + try logger.addURL(Log{ + .url = "https://josias.dev/", + .title = "The blog of josias", + .timestamp = std.time.milliTimestamp(), + }); +} + +test "get logs" { + var logger = try Logger.init(default_allocator, "j"); + const logs = try logger.getLogs(); + for (logs) |log| { + std.debug.print("Log: {}\n", .{log}); + } +} + +test "get logs past a certain date" { + var logger = try Logger.init(default_allocator, "j"); + const logs = try logger.getLogs(); + const newLogs = logger.getFrom(logs, 159760468400); + for (logs) |log| { + std.debug.print("Log: {}\n", .{log}); + } +} diff --git a/ui/index.html b/ui/index.html new file mode 100644 index 0000000..b2419c2 --- /dev/null +++ b/ui/index.html @@ -0,0 +1,16 @@ +<!DOCTYPE html> +<html> +<head> + <title>AccSpy</title> + <meta name="viewport" content="width=device-width, initial-scale=1" /> +</head> +<body> + <input id="username" placeholder="username" /><button id="getLogsButton">Search</button> + + <h1>Logs for <span id="username"></span></h1> + + <table id="logs"></table> + + <script src="words.js"></script> + <script src="script.js"></script> +</body> diff --git a/ui/script.js b/ui/script.js new file mode 100644 index 0000000..1183f49 --- /dev/null +++ b/ui/script.js @@ -0,0 +1,56 @@ +const APIURL = "http://localhost:8080"; + +async function getLogs(username) { + const data = { + username: username, + from: 1, + }; + console.log("Sending " + JSON.stringify(data)); + + const response = await fetch(APIURL + "/getlogs", + { + method: "POST", + cors: "no-cors", + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify(data) + } + ); + return response.json(); +} + +document.getElementById("getLogsButton").addEventListener("click", async function () { + const username = document.getElementById("username").value; + + let logs = await getLogs(username); + logs = logs.reverse(); // reverse with newest first + + let el = document.getElementById("logs"); + el.innerHTML = ""; + + for (i in logs) { + console.log(logs[i].title); + let log = document.createElement("tr"); + log.className = "normal"; + let d = new Date(logs[i].timestamp); + log.innerHTML = "<th>" + d.toISOString() + "</th><th>" + logs[i].title + "</th><th>" + logs[i].url + "</th>"; + + // if the title or url contains questionable + // words, color the text red + for (x in wordListArray) { + if (logs[i].title.toLowerCase().includes(wordListArray[x]) + || logs[i].url.toLowerCase().includes(wordListArray[x]) + ) { + log.style.color = "red"; + } + } + + el.appendChild(log); + } +}); + + + + + diff --git a/ui/words.js b/ui/words.js new file mode 100644 index 0000000..7b5d882 --- /dev/null +++ b/ui/words.js @@ -0,0 +1,501 @@ + +// Warning! Word list below. Contains profanity and other offensive language. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +const wordList = `2g1c +2 girls 1 cup +acrotomophilia +alabama hot pocket +alaskan pipeline +anal +anilingus +anus +apeshit +arsehole +ass +asshole +assmunch +auto erotic +autoerotic +babeland +baby batter +baby juice +ball gag +ball gravy +ball kicking +ball licking +ball sack +ball sucking +bangbros +bangbus +bareback +barely legal +barenaked +bastard +bastardo +bastinado +bbw +bdsm +beaner +beaners +beaver cleaver +beaver lips +beastiality +bestiality +big black +big breasts +big knockers +big tits +bimbos +birdlock +bitch +bitches +black cock +blonde action +blonde on blonde action +blowjob +blow job +blow your load +blue waffle +blumpkin +bollocks +bondage +boner +boob +boobs +booty call +brown showers +brunette action +bukkake +bulldyke +bullet vibe +bullshit +bung hole +bunghole +busty +butt +buttcheeks +butthole +camel toe +camgirl +camslut +camwhore +carpet muncher +carpetmuncher +chocolate rosebuds +cialis +circlejerk +cleveland steamer +clit +clitoris +clover clamps +clusterfuck +cock +cocks +coprolagnia +coprophilia +cornhole +coon +coons +creampie +cum +cumming +cumshot +cumshots +cunnilingus +cunt +darkie +date rape +daterape +deep throat +deepthroat +dendrophilia +dick +dildo +dingleberry +dingleberries +dirty pillows +dirty sanchez +doggie style +doggiestyle +doggy style +doggystyle +dog style +dolcett +domination +dominatrix +dommes +donkey punch +double dong +double penetration +dp action +dry hump +dvda +eat my ass +ecchi +ejaculation +erotic +erotism +escort +eunuch +fag +faggot +fecal +felch +fellatio +feltch +female squirting +femdom +figging +fingerbang +fingering +fisting +foot fetish +footjob +frotting +fuck +fuck buttons +fuckin +fucking +fucktards +fudge packer +fudgepacker +futanari +gangbang +gang bang +gay sex +genitals +giant cock +girl on +girl on top +girls gone wild +goatcx +goatse +god damn +gokkun +golden shower +goodpoop +goo girl +goregasm +grope +group sex +g-spot +guro +hand job +handjob +hard core +hardcore +hentai +homoerotic +honkey +hooker +horny +hot carl +hot chick +how to kill +how to murder +huge fat +humping +incest +intercourse +jack off +jail bait +jailbait +jelly donut +jerk off +jigaboo +jiggaboo +jiggerboo +jizz +juggs +kike +kinbaku +kinkster +kinky +knobbing +leather restraint +leather straight jacket +lemon party +livesex +lolita +lovemaking +make me come +male squirting +masturbate +masturbating +masturbation +menage a trois +milf +missionary position +mong +motherfucker +mound of venus +mr hands +muff diver +muffdiving +nambla +nawashi +negro +neonazi +nigga +nigger +nig nog +nimphomania +nipple +nipples +nsfw +nsfw images +nude +nudity +nutten +nympho +nymphomania +octopussy +omorashi +one cup two girls +one guy one jar +orgasm +orgy +paedophile +paki +panties +panty +pedobear +pedophile +pegging +penis +phone sex +piece of shit +pikey +pissing +piss pig +pisspig +playboy +pleasure chest +pole smoker +ponyplay +poof +poon +poontang +punany +poop chute +poopchute +porn +porno +pornography +prince albert piercing +pthc +pubes +pussy +queaf +queef +quim +raghead +raging boner +rape +raping +rapist +rectum +reverse cowgirl +rimjob +rimming +rosy palm +rosy palm and her 5 sisters +rusty trombone +sadism +santorum +scat +schlong +scissoring +semen +sex +sexcam +sexo +sexy +sexual +sexually +sexuality +shaved beaver +shaved pussy +shemale +shibari +shit +shitblimp +shitty +shota +shrimping +skeet +slanteye +slut +s&m +smut +snatch +snowballing +sodomize +sodomy +spastic +spic +splooge +splooge moose +spooge +spread legs +spunk +strap on +strapon +strappado +strip club +style doggy +suck +sucks +suicide girls +sultry women +swastika +swinger +tainted love +taste my +tea bagging +threesome +throating +thumbzilla +tied up +tight white +tit +tits +titties +titty +tongue in a +topless +tosser +towelhead +tranny +tribadism +tub girl +tubgirl +tushy +twat +twink +twinkie +two girls one cup +undressing +upskirt +urethra play +urophilia +vagina +venus mound +viagra +vibrator +violet wand +vorarephilia +voyeur +voyeurweb +voyuer +vulva +wank +wetback +wet dream +white power +whore +worldsex +wrapping men +wrinkled starfish +xx +xxx +yaoi +yellow showers +yiffy +zoophilia +🖕` + +const wordListArray = wordList.split("\n"); |