Selected Projects
30+ projects across cybersecurity, data analytics, ERP, process modeling, and web — built through coursework, research, and real-world application. Featured projects highlighted below.
Featured Projects
Selected for depth, real-world relevance, and technical complexity.
WooCommerce → GLS Automated Shipping Workflow (No Official API)
GLS Croatia offers no WooCommerce integration and no public API. Built a complete automated order-to-shipping pipeline from scratch using a Chrome browser extension, a Cloudflare Worker, and a WooCommerce code snippet — so every new order on opgbrankomarinov.com auto-fills the GLS shipping form on paket.hr with zero manual data entry.
- Cloudflare Worker receives WooCommerce webhook on new order, formats data, generates pre-filled URL
- Chrome Extension (Manifest v3) injects into paket.hr and reads URL params to fill the form
- Vue.js DOM hack — bypasses framework's input interception using
nativeInputValueSetterso Vue detects the change - Smart address parser splits "Ulica bb 12A" → street + house number automatically
- Phone normalizer strips +385 Croatian prefix; email-to-name fallback if customer name missing
- Sender (OPG Branko Marinov) pre-filled automatically — recipient filled from order data
export default {
async fetch(request) {
const url = new URL(request.url);
const name = url.searchParams.get("name") || "";
const address = url.searchParams.get("address") || "";
const city = url.searchParams.get("city") || "";
const zip = url.searchParams.get("zip") || "";
const email = url.searchParams.get("email") || "";
const phone = (url.searchParams.get("phone") || "")
.replace(/D/g, '')
.replace(/^385/, '')
.slice(-9);
// Name parsing
let parts = name.trim().split(/s+/);
let first = parts[0] || "";
let last = parts.slice(1).join(" ") || "";
if (!first || !last) {
const emailName = email.split("@")[0];
const emailParts = emailName
.replace(/[0-9]/g, '')
.split(/[._-]+/);
if (!first) first = capitalize(emailParts[0] || "");
if (!last) last = capitalize(emailParts[1] || "");
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
// Address split
function splitAddress(full) {
if (!full) return { street: "", number: "" };
const match = full.match(/^(.*?)[s,]+(d+[a-zA-Z]?)/);
if (match) {
return {
street: match[1].trim(),
number: match[2].trim()
};
}
return {
street: full,
number: ""
};
}
const { street, number } = splitAddress(address);
// Build GLS redirect URL
const glsUrl = new URL("https://www.paket.hr/posalji-paket-pl");
// Required — pass full name for extension fallback
glsUrl.searchParams.set("name", name);
// Name parts
glsUrl.searchParams.set("first", first);
glsUrl.searchParams.set("last", last);
glsUrl.searchParams.set("address", address);
// Address parts
glsUrl.searchParams.set("street", street);
glsUrl.searchParams.set("house", number);
glsUrl.searchParams.set("city", city);
glsUrl.searchParams.set("zip", zip);
glsUrl.searchParams.set("phone", phone);
glsUrl.searchParams.set("email", email);
return Response.redirect(glsUrl.toString(), 302);
}
};
function setValue(el, value) {
if (!el) return;
el.focus();
const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value"
).set;
nativeInputValueSetter.call(el, value);
el.dispatchEvent(new Event('input', { bubbles: true }));
el.dispatchEvent(new Event('change', { bubbles: true }));
el.blur();
}
function waitFor(selector, callback, timeout = 10000) {
const start = Date.now();
const interval = setInterval(() => {
const el = document.querySelector(selector);
if (el) {
clearInterval(interval);
callback(el);
}
if (Date.now() - start > timeout) {
clearInterval(interval);
console.log("Timeout:", selector);
}
}, 200);
}
function cleanPhone(phone) {
return phone.replace(/\D/g, '').replace(/^385/, '').slice(-9);
}
function splitAddress(full) {
if (!full) return { street: "", number: "" };
const match = full.match(/^(.*?)[\s,]+(\d+[a-zA-Z]?)/);
if (match) {
return {
street: match[1].trim(),
number: match[2].trim()
};
}
return {
street: full,
number: ""
};
}
function nameFromEmail(email) {
if (!email) return { first: "", last: "" };
const namePart = email.split("@")[0];
const parts = namePart
.replace(/[0-9]/g, '')
.split(/[._-]+/);
return {
first: capitalize(parts[0] || ""),
last: capitalize(parts[1] || "")
};
}
function capitalize(str) {
return str ? str.charAt(0).toUpperCase() + str.slice(1) : "";
}
const params = new URLSearchParams(window.location.search);
const name = params.get("name") || "";
const address = params.get("address") || "";
const city = params.get("city") || "";
const zip = params.get("zip") || "";
const phone = cleanPhone(params.get("phone") || "");
const email = params.get("email") || "";
let parts = name.trim().split(/\s+/);
let first = parts[0] || "";
let last = parts.slice(1).join(" ") || "";
// fallback if name is missing
if (!first || !last) {
const fromEmail = nameFromEmail(email);
first = first || fromEmail.first;
last = last || fromEmail.last;
}
const { street, number } = splitAddress(address);
waitFor('button[aria-label="Pravna osoba"]', (btn) => {
btn.click();
waitFor('#company', (el) => {
setValue(el, 'OPG Branko Marinov');
});
waitFor('#first_name', (el) => setValue(el, 'Branko'));
waitFor('#last_name', (el) => setValue(el, 'Marinov'));
waitFor('#email', (el) => setValue(el, 'opgbranko1@gmail.com'));
waitFor('#phone', (el) => setValue(el, '998211395'));
waitFor('#address', (el) => setValue(el, 'Gornji Vezac'));
waitFor('#house_number', (el) => setValue(el, '18'));
waitFor('#city', (el) => setValue(el, 'Primošten'));
waitFor('#zip', (el) => setValue(el, '22202'));
waitFor('#vat-sender', (el) => setValue(el, '42614167398'));
});
waitFor('#first-name', () => {
const firstNames = document.querySelectorAll('#first-name');
const lastNames = document.querySelectorAll('#last-name');
// email has duplicate IDs — use type selector
const emails = document.querySelectorAll('input[type="email"]');
const phones = document.querySelectorAll('#phone-number');
const streets = document.querySelectorAll('#street-address');
const houses = document.querySelectorAll('#house-number');
const cities = document.querySelectorAll('#city');
const zips = document.querySelectorAll('#zip');
const i = firstNames.length - 1;
// Name parts
setValue(firstNames[i], first);
setValue(lastNames[i], last);
// email — last occurrence is recipient
setValue(emails[emails.length - 1], email);
// phone
setValue(phones[phones.length - 1], phone);
// address
setValue(streets[streets.length - 1], street);
setValue(houses[houses.length - 1], number);
// city / zip
setValue(cities[cities.length - 1], city);
setValue(zips[zips.length - 1], zip);
});
add_action('woocommerce_order_item_add_action_buttons', 'gls_worker_button');
function gls_worker_button($order) {
if (!$order) return;
$first = $order->get_shipping_first_name() ?: $order->get_billing_first_name();
$last = $order->get_shipping_last_name() ?: $order->get_billing_last_name();
$url = "https://glsautomate.opgbranko1.workers.dev?" . http_build_query([
'name' => trim($first . ' ' . $last),
'address' => $order->get_shipping_address_1(),
'city' => $order->get_shipping_city(),
'zip' => $order->get_shipping_postcode(),
'phone' => $order->get_billing_phone(),
'email' => $order->get_billing_email()
]);
echo '<a href="'.$url.'" target="_blank" class="button button-primary" style="margin-left:10px;">
GLS AUTO
</a>';
}
Scam Checker HR — Phishing & Fraud Detection Tool Croatian-language · No Backend
A fully client-side Croatian phishing and fraud detection platform with four analysis modules: text, URL, email header, and file scanning. All processing runs in the browser — no data is sent to any server. External threat intelligence (Google Safe Browsing, URLhaus, MalwareBazaar, RDAP) is proxied through a Cloudflare Pages Function to keep API keys private.
- URL analysis: HTTPS check, raw IP, suspicious TLD, brand impersonation, typosquatting, URL shorteners
- Email header parser: SPF / DKIM / DMARC validation, From ↔ Return-Path mismatch, brand impersonation detection
- File scanner: magic bytes (MZ/ELF/OLE/ZIP), SHA-256 hashing, suspicious string patterns (PowerShell, VirtualAlloc, eval)
- External APIs: Google Safe Browsing v4, URLhaus (abuse.ch), MalwareBazaar — all proxied via Cloudflare, key never exposed
- Risk scoring engine: 0–3 low · 4–8 suspicious · 9+ high risk — with localised Croatian advice & emergency contacts
function analyzeURL(rawUrl) {
let score = 0;
const flags = [], positives = [];
const url = /^https?:\/\//i.test(rawUrl)
? rawUrl : 'https://' + rawUrl;
const parsed = new URL(url);
const host = parsed.hostname.toLowerCase();
// --- HTTPS ---
if (!/^https:\/\//i.test(rawUrl)) {
score += 2;
flags.push('Nema HTTPS enkripcije');
} else {
positives.push('HTTPS veza');
}
// --- Raw IP address ---
if (/^\d{1,3}(\.\d{1,3}){3}$/.test(host)) {
score += 4;
flags.push('Direktna IP adresa umjesto domene');
}
// --- Brand impersonation ---
const BRANDS = ['paypal','google','microsoft','amazon',
'netflix','hac','porezna','fina','zaba'];
const domain = host.replace(/^www\./, '');
for (const brand of BRANDS) {
if (domain.includes(brand) &&
!HR_WHITELIST.includes(domain)) {
score += 5;
flags.push(`Moguca imitacija branda: ${brand}`);
break;
}
}
// --- Typosquatting (Levenshtein distance) ---
for (const legit of HR_WHITELIST) {
if (levenshtein(domain, legit) === 1) {
score += 6;
flags.push(`Typosquatting: slicno kao ${legit}`);
break;
}
}
// --- URL shortener ---
const SHORTENERS = ['bit.ly','tinyurl.com','t.co','ow.ly'];
if (SHORTENERS.some(s => host.endsWith(s))) {
score += 2;
flags.push('Skracivac URL-a — skriva odrediste');
}
return { score, flags, positives };
}
async function analyzeFile(file) {
const MAX = 512;
const buf = await file.slice(0, MAX).arrayBuffer();
const bytes = new Uint8Array(buf);
// ── Magic bytes detection ──────────────────────
const MZ = bytes[0]===0x4D && bytes[1]===0x5A; // PE/EXE/DLL
const ELF = bytes[0]===0x7F && bytes[1]===0x45; // Linux binary
const SHEBANG = bytes[0]===0x23 && bytes[1]===0x21; // #!/...
const OLE = bytes[0]===0xD0 && bytes[1]===0xCF; // Office macro doc
const ZIP = bytes[0]===0x50 && bytes[1]===0x4B; // ZIP / DOCX / JAR
if (MZ) { score += 8; flags.push('Izvršna Windows datoteka (PE)'); }
if (ELF) { score += 8; flags.push('Izvršna Linux datoteka (ELF)'); }
if (OLE) { score += 6; flags.push('Stari Office format — može sadržavati makroe'); }
// ── SHA-256 via SubtleCrypto (no server needed) ─
const fullBuf = await file.arrayBuffer();
const hashBuf = await crypto.subtle.digest('SHA-256', fullBuf);
const sha256 = [...new Uint8Array(hashBuf)]
.map(b => b.toString(16).padStart(2, '0')).join('');
// ── Query MalwareBazaar by hash ────────────────
const mbResult = await malwareBazaarCheck(sha256);
if (mbResult.found) {
score += 10;
flags.push(`Hash pronaden u MalwareBazaar: ${mbResult.tags.join(', ')}`);
}
// ── Suspicious strings scan ────────────────────
const text = new TextDecoder('utf-8', { fatal: false }).decode(buf);
const SUSPICIOUS = [
/powershell/i, /VirtualAlloc/i, /base64/i,
/webclient/i, /downloadstring/i, /invoke-expression/i
];
for (const re of SUSPICIOUS) {
if (re.test(text)) {
score += 3;
flags.push(`Sumnjiv string: ${re.source}`);
}
}
return { score, flags, sha256 };
}
// Cloudflare Pages Function — proxy for Google Safe Browsing v4
// API key stored in CF env var GSB_API_KEY — never reaches the browser
export async function onRequestPost(context) {
const { request, env } = context;
const cors = { 'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*' };
const apiKey = env.GSB_API_KEY;
if (!apiKey) return new Response(
JSON.stringify({ _status: 'not_configured' }),
{ status: 503, headers: cors }
);
const { url } = await request.json();
const gsbRes = await fetch(
`https://safebrowsing.googleapis.com/v4/threatMatches:find?key=${apiKey}`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
client: { clientId: 'scam-checker-hr', clientVersion: '1.0' },
threatInfo: {
threatTypes: ['MALWARE', 'SOCIAL_ENGINEERING',
'UNWANTED_SOFTWARE'],
platformTypes: ['ANY_PLATFORM'],
threatEntryTypes: ['URL'],
threatEntries: [{ url }],
},
}),
}
);
// Forward Google's response — key stays server-side
return new Response(await gsbRes.text(),
{ status: 200, headers: cors });
}
Phishing Campaign Framework: OSINT Integration & Automated Attack Simulation
Built a complete, end-to-end framework for conducting realistic phishing simulations. The system combines OSINT (Open Source Intelligence) data collection with automated attack scenario generation to assess organizational security awareness and resilience — designed specifically for controlled red teaming exercises and security training programs.
- OSINT pipeline: Google dorking operators, automated web scraping, target data aggregation
- Automated phishing scenario builder from collected intelligence data
- Security awareness evaluation methodology for organizations
- Comparative analysis of existing frameworks (GoPhish, Evilginx, etc.)
- 95-page research thesis — University of Zagreb, FOI Varaždin, Dec 2025
OTP banka — Information Security Department Internship
20-day professional internship embedded in the Information Security team of OTP banka d.d., one of Croatia's largest banks. Worked hands-on with enterprise-grade security tooling used in daily banking operations — from SIEM monitoring to vulnerability management and physical infrastructure tours.
- IBM QRadar SIEM: log source configuration, offense investigation, custom rule creation
- Qualys vulnerability scan of internal network — identified and triaged 270+ vulnerabilities
- Symantec Mail Security Gateway: e-mail filtering configuration and threat analysis
- USB device access control via Symantec DLP system
- Participated in SWIFT Learning Services presentation on interbank communications
- Nmap-based internal scanning, DMZ architecture review, Check Point & Fortinet systems
Threat Hunting — Full Lab Environment & Attack Simulations
Built and documented a complete threat hunting environment covering the full detection lifecycle. Deployed endpoint security tools, SIEM, honeypots, and sandbox environments, then ran real attack simulations to validate detection capabilities.
- pfSense firewall setup with brute force attack simulation and detection
- Pentbox honeypot + DVWA SQL injection — practical exploitation and detection
- Malware traffic analysis on infected machine using Wireshark
- Kali Linux sandboxing and NIDS (Network Intrusion Detection) configuration
- Covered: EPP, EDR, XDR, SIEM principles, honeypot taxonomy, sandboxing
Microsoft Dynamics 365 Business Central — Full ERP Simulation
End-to-end business operations simulation using Microsoft Dynamics 365 Business Central. Configured and executed a full business cycle — procurement, sales, and financial reporting — with multi-currency accounts and detailed analytics output.
- Multi-currency bank account setup (EUR, USD, HRK)
- Procurement cycle: purchase orders, supplier management, document tracking
- Sales cycle: invoicing, customer accounts, revenue reporting
- Financial statements and analytics — balance sheets, cash flow
LA Crime Data Analysis — ETL, Data Warehouse & Tableau
Built a full data analytics pipeline on the Los Angeles crime dataset (2020–present) from Kaggle. Designed a star-schema data warehouse, implemented ETL, and created interactive Tableau dashboards revealing crime patterns, demographics, and hotspots.
- Star-schema data warehouse design on Microsoft SQL Server
- ETL pipeline: data cleaning, transformation, loading (600K+ records)
- Tableau dashboards: crime by type, location, gender, time-of-day
- Key findings: crime concentration zones, seasonal patterns, gender distribution
Sports Team Rankings Using the PageRank Algorithm
Applied Google's PageRank algorithm — originally designed for web page ranking — to rank national football teams from the 2022 FIFA World Cup in Qatar. Grounded in graph theory, Markov chains, and the Perron-Frobenius theorem.
- Graph-based model: teams as nodes, match results as weighted directed edges
- Markov chain convergence analysis and power iteration method
- Comparison of PageRank rankings vs. FIFA official rankings
- 39-page academic thesis — University of Zagreb, FOI Varaždin, 2023
Other Projects
Academic and coursework projects covering the full breadth of IT, business, and systems curriculum. Each is downloadable — PDFs can be previewed directly in the browser.
Attacks on RSA Cryptography
Analysis of mathematical attacks on the RSA algorithm — factorization, timing, and chosen-ciphertext. Includes formal problem statements and proofs.
Digital Transformation — Gradska tržnica Daruvar
Full digital transformation analysis for a public market company: industry analysis, disruption mapping, problem identification, and transformation roadmap.
Business Process Modeling — Project Approval
BPMN process model for a project approval workflow built in Camunda. Includes data models, business logic, and process flow documentation.
Software Engineering — Mobile Locator App
Full software requirements specification (SRS) and design document for a mobile device localization system in secure facilities. Use-case diagrams, data models, and architecture.
Strategic Management — LuxSolis Energetica
Comprehensive strategic management project for a fictional renewable energy company. SWOT, Porter's Five Forces, competitive positioning, and strategic roadmap.
Project Management — IT Project Plan
Full project management plan including scope definition, WBS, risk register, stakeholder analysis, and timeline for an IT system implementation project.
Digital Marketing Campaign & Budget
Full digital marketing campaign plan with financial budget projection. Includes channel strategy, KPIs, content plan, and ROI analysis.
TQM — Total Quality Management System Design
Design and analysis of a Total Quality Management system for an organization. Covers quality principles, process improvement, and implementation strategy.
Security in Solidity — Smart Contract Vulnerabilities
Analysis of common smart contract security vulnerabilities in Solidity. Covers reentrancy attacks, integer overflow, access control flaws, and mitigation strategies on the Ethereum blockchain.
Statistical Data Analysis (R / HTML)
Three-part statistical analysis project using R. Covers descriptive statistics, hypothesis testing, regression analysis, and data visualization.
Financial Mathematics — Quantitative Models
Applied financial mathematics covering time value of money, annuities, bond valuation, and portfolio optimization models.
Business Process & Data Modeling (MPP)
Comprehensive business process and data modeling project. Entity-relationship diagrams, process flow models, and system architecture documentation.
IT Service Management — Test Scenarios
Detailed test scenario documentation for IT service management processes. Covers ITIL-aligned incident, change, and problem management workflows.
CRATIS — Digital Innovation Project
Team project analyzing digital innovation opportunities using CRATIS framework. Includes stakeholder mapping, value chain analysis, and digital capability assessment.
Undergraduate Internship Report
Professional practice diary from undergraduate internship. Documents tasks, professional development, and applied learning in a business environment.