Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tabtracker #47

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
71 changes: 71 additions & 0 deletions submissions/tab-tracker/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
let userId = null;

// Load userId from chrome storage when the background script starts
chrome.storage.local.get(['userId'], (result) => {
if (result.userId) {
userId = result.userId;
startTrackingTabs();
}
});

// Listener for the login event
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.action === 'login') {
userId = request.userId;

// Store userId in chrome.storage
chrome.storage.local.set({ userId: userId }, () => {
console.log('User ID saved in background script.');
});

startTrackingTabs();
sendResponse({ status: 'Tracking started' });
}
});

// Function to start tracking tabs indefinitely
function startTrackingTabs() {
setInterval(async () => {
if (!userId) return; // Stop tracking if user is not logged in

const tabs = await chrome.tabs.query({});
tabs.forEach(async (tab) => {
const tabVisited = tab.url; // URL of the visited tab
await trackActivity(userId, tabVisited);
});
}, 10000); // Check every 10 seconds
}

// Function to log activity to your server
async function trackActivity(userId, tabVisited) {
if (tabVisited) {
await fetch('https://d1af270f-5b2a-4e81-97ef-1383b66ba676-00-1an6e8o4o3ogo.worf.replit.dev/track', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ userId, tabVisited })
});
}
}

async function loadRules() {
const response = await fetch(chrome.runtime.getURL('rules.json'));
const rules = await response.json();

// Remove existing rules before adding new ones
const ruleIds = rules.map(rule => rule.id);
chrome.declarativeNetRequest.updateDynamicRules({
removeRuleIds: ruleIds,
addRules: rules
}, () => {
if (chrome.runtime.lastError) {
console.error("Error loading rules:", chrome.runtime.lastError);
} else {
console.log("Rules loaded successfully");
}
});
}
Comment on lines +52 to +68
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does it do? and why do you need this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part of the code loads the websites that can be accessed by the students. I put the list in a separate file because I'm planning to add a feature to the dashboard where the teacher can change the sites the students can access(like for a different class, you might need to have canva open)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay. Keep working on it then


// Call the function to load the rules
loadRules();
90 changes: 90 additions & 0 deletions submissions/tab-tracker/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
document.addEventListener('DOMContentLoaded', async () => {
// Check if the user is already logged in
chrome.storage.local.get(['userId'], (result) => {
if (result.userId) {
document.getElementById('loginForm').style.display = 'none';
document.getElementById('signupForm').style.display = 'none';
document.getElementById('successMessage').style.display = 'block';
} else {
document.getElementById('loginForm').style.display = 'block';
}
});

// Toggle between login and signup forms
document.getElementById('toggleToSignup').addEventListener('click', () => {
document.getElementById('loginForm').style.display = 'none';
document.getElementById('signupForm').style.display = 'block';
});

document.getElementById('toggleToLogin').addEventListener('click', () => {
document.getElementById('signupForm').style.display = 'none';
document.getElementById('loginForm').style.display = 'block';
});

// Handle login
document.getElementById('loginButton').addEventListener('click', async () => {
const username = document.getElementById('loginUsername').value;
const password = document.getElementById('loginPassword').value;

const response = await fetch('https://d1af270f-5b2a-4e81-97ef-1383b66ba676-00-1an6e8o4o3ogo.worf.replit.dev/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});

if (response.ok) {
const data = await response.json();
const userId = data.userId;

// Store the userId in chrome.storage
chrome.storage.local.set({ userId: userId }, () => {
console.log('User ID saved.');

// Hide the forms and show the success message
document.getElementById('loginForm').style.display = 'none';
document.getElementById('signupForm').style.display = 'none';
document.getElementById('successMessage').style.display = 'block';
});

// Send the userId to the background script
chrome.runtime.sendMessage({ action: 'login', userId: userId });
} else {
alert('Login failed. Please check your credentials.');
}
});

// Handle signup
document.getElementById('signupButton').addEventListener('click', async () => {
const username = document.getElementById('signupUsername').value;
const password = document.getElementById('signupPassword').value;

const response = await fetch('https://d1af270f-5b2a-4e81-97ef-1383b66ba676-00-1an6e8o4o3ogo.worf.replit.dev/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ username, password })
});

if (response.ok) {
const data = await response.json();
const userId = data.userId;

// Store the userId in chrome.storage
chrome.storage.local.set({ userId: userId }, () => {
console.log('User ID saved.');

// Hide the forms and show the success message
document.getElementById('signupForm').style.display = 'none';
document.getElementById('successMessage').style.display = 'block';
});

// Send the userId to the background script
chrome.runtime.sendMessage({ action: 'login', userId: userId });
} else {
alert('Signup failed. Please try again.');
}
});
});
31 changes: 31 additions & 0 deletions submissions/tab-tracker/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"manifest_version": 3,
"name": "Activity Tracker",
"version": "1.0",
"permissions": [
"storage",
"tabs",
"activeTab",
"declarativeNetRequest",
"declarativeNetRequestFeedback",
"webRequest"
],
"background": {
"service_worker": "background.js"
},
"action": {
"default_popup": "popup.html"
},
"declarative_net_request": {
"rule_resources": [
{
"id": "ruleset_1",
"enabled": true,
"path": "rules.json"
}
]
},
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'"
}
}
54 changes: 54 additions & 0 deletions submissions/tab-tracker/popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Activity Tracker</title>
<script src="main.js" defer></script>
<style>
body {
font-family: Arial, sans-serif;
margin: 20px;
background-color: #f4f4f4;
}
.form-container {
display: none;
}
#loginForm {
display: block;
}
#successMessage {
display: none;
color: green;
}
#toggleForm {
margin-top: 10px;
cursor: pointer;
color: blue;
text-decoration: underline;
}
</style>
</head>
<body>
<div id="loginForm" class="form-container">
<h2>Login</h2>
<input type="text" id="loginUsername" placeholder="Username" required>
<input type="password" id="loginPassword" placeholder="Password" required>
<button id="loginButton">Login</button>
<p id="toggleToSignup">Don't have an account? Sign up here.</p>
</div>

<div id="signupForm" class="form-container">
<h2>Sign Up</h2>
<input type="text" id="signupUsername" placeholder="Username" required>
<input type="password" id="signupPassword" placeholder="Password" required>
<button id="signupButton">Sign Up</button>
<p id="toggleToLogin">Already have an account? Login here.</p>
</div>

<div id="successMessage">
<h2>Welcome!</h2>
<p>You are now logged in and your activity is being tracked.</p>
</div>
</body>
</html>
62 changes: 62 additions & 0 deletions submissions/tab-tracker/rules.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
[
{
"id": 1,
"condition": {
"urlFilter": "harker.org",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume these are websites that are automatically tracked? What if someone wants to change the rules or remove some?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, these are the websites that the students can open - all others are blocked. When on one of these domains, any part of the website accessed is sent to the database and is visible to the teacher on the dashboard. I'm planning to add the feature to the teacher dashboard soon where the teacher can change the allowed urls - right now its just a pre-set list.

"resourceTypes": ["main_frame"]
},
"action": {
"type": "allow"
}
},
{
"id": 2,
"condition": {
"urlFilter": "google.com",
"resourceTypes": ["main_frame"]
},
"action": {
"type": "allow"
}
},
{
"id": 3,
"condition": {
"urlFilter": "nytimes.com",
"resourceTypes": ["main_frame"]
},
"action": {
"type": "allow"
}
},
{
"id": 4,
"condition": {
"urlFilter": "replit.com",
"resourceTypes": ["main_frame"]
},
"action": {
"type": "block"
}
},
{
"id": 5,
"condition": {
"urlFilter": "membean.com",
"resourceTypes": ["main_frame"]
},
"action": {
"type": "block"
}
},
{
"id": 6,
"condition": {
"urlFilter": ".*",
"resourceTypes": ["main_frame"]
},
"action": {
"type": "block"
}
}
]