mirror of
https://github.com/dafthack/GraphRunner
synced 2026-06-08 13:44:02 +00:00
1861 lines
64 KiB
HTML
1861 lines
64 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>GraphRunner</title>
|
|
<style>
|
|
body {
|
|
font-family: Courier, sans-serif;
|
|
margin: 0;
|
|
padding: 0;
|
|
background-color: #303030;
|
|
color: #ffffff;
|
|
}
|
|
.container {
|
|
max-width: 1000px;
|
|
margin: 0 auto;
|
|
padding: 20px;
|
|
background-color: #505050;
|
|
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.2);
|
|
}
|
|
h1 {
|
|
text-align: center;
|
|
margin-bottom: 20px;
|
|
color: #FFFFFF;
|
|
}
|
|
h3 {
|
|
text-align: center;
|
|
margin-bottom: 20px;
|
|
color: #FFFFFF;
|
|
}
|
|
label {
|
|
font-weight: bold;
|
|
}
|
|
input[type="text"]{
|
|
padding: 8px;
|
|
font-size: 14px;
|
|
border-radius: 4px;
|
|
border: 1px solid #ccc;
|
|
background-color: #fff;
|
|
width: 100%;
|
|
max-width: 400px;
|
|
}
|
|
input[type="submit"],
|
|
textarea,
|
|
select {
|
|
width: 100%;
|
|
padding: 10px;
|
|
margin-bottom: 10px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
}
|
|
input[type="file"] {
|
|
padding: 5px;
|
|
}
|
|
button {
|
|
padding: 10px 20px;
|
|
background-color: #357EC7;
|
|
color: #000;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
button:hover {
|
|
background-color: #B4CFEC;
|
|
}
|
|
.response {
|
|
border: 1px solid #ccc;
|
|
padding: 4px;
|
|
border-radius: 4px;
|
|
background-color: #303030;
|
|
white-space: pre-wrap;
|
|
}
|
|
.item-list {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 20px;
|
|
}
|
|
|
|
.item-card {
|
|
border: 1px solid #ccc;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
width: 200px;
|
|
background-color: #fff;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
|
}
|
|
|
|
.item-card:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.item-thumbnail {
|
|
max-width: 100%;
|
|
height: auto;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.item-title {
|
|
font-size: 18px;
|
|
font-weight: bold;
|
|
margin: 8px 0;
|
|
}
|
|
|
|
.item-description {
|
|
font-size: 14px;
|
|
color: #666;
|
|
}
|
|
|
|
.item-action {
|
|
display: inline-block;
|
|
padding: 6px 12px;
|
|
background-color: #007bff;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 4px;
|
|
text-decoration: none;
|
|
font-size: 14px;
|
|
transition: background-color 0.2s ease-in-out;
|
|
}
|
|
|
|
.item-action:hover {
|
|
background-color: #0056b3;
|
|
}
|
|
/* Email Viewer Styles */
|
|
.email-controls {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.search-input {
|
|
flex: 1;
|
|
padding: 10px;
|
|
border: 1px solid #ccc;
|
|
border-radius: 0px;
|
|
font-size: 14px;
|
|
margin-right: 10px;
|
|
max-width: 40%;
|
|
}
|
|
|
|
.search-button {
|
|
padding: 10px 20px;
|
|
background-color: #357EC7;
|
|
color: #000;
|
|
border: none;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.search-button:hover {
|
|
background-color: #B4CFEC;
|
|
}
|
|
|
|
.email-list {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(600px, 1fr));
|
|
gap: 8px;
|
|
}
|
|
|
|
.email-summary {
|
|
padding: 10px;
|
|
border: 1px solid #ccc;
|
|
background-color: #303030;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
|
}
|
|
|
|
.email-summary:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.email-detail {
|
|
margin-top: 20px;
|
|
padding: 4px;
|
|
border: 1px solid #ccc;
|
|
background-color: #dddddd;
|
|
border-radius: 4px;
|
|
color: #000000;
|
|
}
|
|
|
|
.email-detail h3 {
|
|
margin-bottom: 10px;
|
|
color: #000000;
|
|
}
|
|
|
|
.email-detail strong {
|
|
font-weight: bold;
|
|
}
|
|
|
|
.email-detail p {
|
|
margin: 10px 0;
|
|
font-size: 14px;
|
|
color: #FFFFFF;
|
|
}
|
|
|
|
.email-detail a {
|
|
color: #B0E0E6;
|
|
text-decoration: none;
|
|
transition: color 0.2s ease-in-out;
|
|
}
|
|
|
|
.email-detail a:hover {
|
|
color: #0056b3;
|
|
}
|
|
select#httpMethod {
|
|
padding: 8px;
|
|
font-size: 14px;
|
|
border-radius: 4px;
|
|
border: 1px solid #ccc;
|
|
background-color: #fff;
|
|
width: 100%;
|
|
max-width: 80px;
|
|
}
|
|
#chatViewer {
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.chat-summary {
|
|
border: 1px solid #ccc;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
width: 100%;
|
|
background-color: #303030;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
|
cursor: pointer;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.chat-summary:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
#chatMessages {
|
|
border: 1px solid #ccc;
|
|
padding: 10px;
|
|
background-color: #f9f9f9;
|
|
border-radius: 4px;
|
|
margin-top: 20px;
|
|
color: #000000;
|
|
}
|
|
.message {
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
margin-bottom: 10px;
|
|
padding: 10px;
|
|
background-color: #f9f9f9;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.message-header {
|
|
font-weight: bold;
|
|
margin-bottom: 5px;
|
|
}
|
|
|
|
.message-content {
|
|
margin-top: 5px;
|
|
}
|
|
|
|
/* Style for image attachments */
|
|
.message-content img {
|
|
max-width: 100%;
|
|
height: auto;
|
|
border: 1px solid #ccc;
|
|
border-radius: 4px;
|
|
margin-top: 5px;
|
|
}
|
|
|
|
/* Style for file links */
|
|
.message-content a {
|
|
color: #007bff;
|
|
text-decoration: none;
|
|
transition: color 0.2s ease-in-out;
|
|
}
|
|
|
|
.message-content a:hover {
|
|
color: #0056b3;
|
|
}
|
|
.file-card {
|
|
border: 1px solid #ccc;
|
|
padding: 10px;
|
|
margin: 10px 0;
|
|
background-color: #f9f9f9;
|
|
border-radius: 5px;
|
|
box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.1);
|
|
}
|
|
|
|
.file-name {
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.file-details {
|
|
margin-top: 5px;
|
|
font-size: 14px;
|
|
color: #666;
|
|
}
|
|
|
|
.file-link {
|
|
color: #007bff;
|
|
text-decoration: none;
|
|
}
|
|
.item-name {
|
|
font-weight: bold;
|
|
color: #333;
|
|
}
|
|
|
|
.item-details {
|
|
margin-top: 5px;
|
|
font-size: 14px;
|
|
color: #666;
|
|
}
|
|
.sharepoint-drive-summary {
|
|
border: 1px solid #ccc;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
width: 100%;
|
|
background-color: #303030;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
|
cursor: pointer;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.sharepoint-drive-summary:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
.sharepoint-item-summary {
|
|
border: 1px solid #ccc;
|
|
border-radius: 8px;
|
|
padding: 10px;
|
|
width: 100%;
|
|
background-color: #303030;
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
transition: transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out;
|
|
cursor: pointer;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.sharepoint-item-summary:hover {
|
|
transform: translateY(-5px);
|
|
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="container">
|
|
<h1>GraphRunner</h1>
|
|
<h3>A GUI for the Microsoft Graph API</h3>
|
|
<!-- Token Input -->
|
|
<label for="token">Access Token:</label>
|
|
<input type="text" id="token" name="token" required>
|
|
<button id="parseTokenButton">Parse Token</button>
|
|
<pre class="response" id="jwtFields"></pre>
|
|
|
|
|
|
<hr>
|
|
|
|
<!-- API Request Form -->
|
|
<h2>Custom API Request</h2>
|
|
<form id="apiRequestForm">
|
|
<label for="apiEndpoint">API Endpoint:</label>
|
|
<input type="text" id="apiEndpoint" name="apiEndpoint" value="https://graph.microsoft.com/v1.0/me" required>
|
|
|
|
<!-- Dropdown for HTTP Method -->
|
|
<label for="httpMethod">HTTP Method:</label>
|
|
<select id="httpMethod" name="httpMethod">
|
|
<option value="GET">GET</option>
|
|
<option value="POST">POST</option>
|
|
<option value="PUT">PUT</option>
|
|
<option value="OPTIONS">OPTIONS</option>
|
|
</select>
|
|
|
|
<!-- Additional input for POST/PUT request body -->
|
|
<label for="requestBody" id="requestBodyLabel">Request Body:</label>
|
|
<textarea id="requestBody" name="requestBody" rows="4"></textarea>
|
|
|
|
<button type="submit">Send Request</button>
|
|
</form>
|
|
|
|
<pre class="response" id="apiResponse"></pre>
|
|
<hr>
|
|
|
|
<!-- List All Users Button -->
|
|
<h2>Directory - Users</h2>
|
|
<button id="listUsersButton">List Users</button>
|
|
<button id="exportUsersButton">Export</button>
|
|
<pre class="response" id="listUsersResponse"></pre>
|
|
<hr>
|
|
|
|
<div id="groupExplorerContainer" class="group-explorer">
|
|
<div class="group-explorer-header">
|
|
<h2>Directory - Groups</h2>
|
|
<button id="listGroupsButton">List Groups</button>
|
|
<button id="exportButton">Export</button>
|
|
</div>
|
|
<div id="groupList" class="group-list"></div>
|
|
<div id="groupMembers" class="group-members"></div>
|
|
</div>
|
|
|
|
<!-- Email Viewer -->
|
|
<h2>Email Viewer (Current User)</h2>
|
|
<button id="fetchEmailsButton">Fetch Emails</button>
|
|
<button id="exportEmailsButton">Export</button>
|
|
<button id="searchButton" class="search-button">Search</button>
|
|
<br></br>
|
|
<div class="email-controls">
|
|
<input type="text" id="searchInput" class="search-input" placeholder="Search emails...">
|
|
|
|
</div>
|
|
<div class="email-list" id="emailList"></div>
|
|
<div class="email-detail" id="emailDetail"></div>
|
|
<hr>
|
|
|
|
<!-- Other User Email Viewer -->
|
|
<h2>Email Viewer (Other Users)</h2>
|
|
<form id="customEmailViewerForm">
|
|
<label for="customUserId">User ID:</label>
|
|
<br>
|
|
<input type="text" id="customUserId" name="customUserId" required>
|
|
<br></br>
|
|
<label for="customFolder">Folder:</label>
|
|
<br>
|
|
<input type="text" id="customFolder" name="customFolder" value="Inbox" required>
|
|
<br></br>
|
|
<button type="submit">Fetch Emails</button>
|
|
</form>
|
|
<div id="customEmailList"></div>
|
|
<div id="customEmailDetail"></div>
|
|
<hr>
|
|
|
|
<!-- Send Email Form -->
|
|
<h2>Send Email</h2>
|
|
<form id="sendEmailForm">
|
|
<label for="to">To:</label>
|
|
<input type="text" id="to" name="to" required>
|
|
<label for="subject">Subject:</label>
|
|
<input type="text" id="subject" name="subject" required>
|
|
<label for="body">Body:</label>
|
|
<textarea id="body" name="body" rows="4" required></textarea>
|
|
<label for="attachments">Attachments:</label>
|
|
<input type="file" id="attachments" name="attachments" multiple>
|
|
<button type="submit">Send Email</button>
|
|
</form>
|
|
<pre class="response" id="sendEmailResponse"></pre>
|
|
<hr>
|
|
|
|
<!-- Button to Fetch Teams Chats -->
|
|
<h2>Teams Chat Viewer (Direct Messages and Group Chat)</h2>
|
|
<div id="chatViewer">
|
|
<!-- Fetch Chats Button -->
|
|
<button id="fetchChatsButton">Fetch Teams Chats</button>
|
|
<!-- Chat List -->
|
|
<div id="chatList" class="item-list"></div>
|
|
<!-- Chat Messages -->
|
|
<div id="chatMessages" class="item-list"></div>
|
|
<!-- Send Message Form -->
|
|
<h4>Send Message to Teams Chat:</h4>
|
|
<input type="text" id="messageTextBox" placeholder="Type your message...">
|
|
<button id="sendMessageButton">Send Message</button>
|
|
</div>
|
|
<hr>
|
|
|
|
<!-- List Public Teams Chats -->
|
|
<h2>Teams Chat Viewer (Org Teams)</h2>
|
|
<button id="listPublicChatsButton">List Public Chats</button>
|
|
<div id="publicChatList"></div>
|
|
<!-- Chat Messages -->
|
|
<div id="publicChatMessages"></div>
|
|
<hr>
|
|
|
|
|
|
<!-- List OneDrive Files and Folders -->
|
|
<h2>OneDrive My Files</h2>
|
|
<button id="listFilesButton">List Files</button>
|
|
<div id="fileList"></div>
|
|
<hr>
|
|
|
|
<!-- List OneDrive Shared Files -->
|
|
<h2>OneDrive Shared Files</h2>
|
|
<button id="listSharedFilesButton">List Shared Files</button>
|
|
<div id="sharedFileList"></div>
|
|
<hr>
|
|
|
|
|
|
<!-- List SharePoint Files and Folders -->
|
|
<h2>SharePoint</h2>
|
|
<button id="listDrivesButton">List SharePoint Root Drives</button>
|
|
<div id="driveList"></div>
|
|
<div id="sharePointDriveFileList"></div>
|
|
<br>
|
|
<button id="listSitesButton">List SharePoint Sites</button>
|
|
<div id="siteList"></div>
|
|
<div id="sharePointfileList"></div>
|
|
<hr>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<script>
|
|
const tokenInput = document.getElementById('token');
|
|
const apiRequestForm = document.getElementById('apiRequestForm');
|
|
const apiResponse = document.getElementById('apiResponse');
|
|
const fetchEmailsButton = document.getElementById('fetchEmailsButton');
|
|
const emailList = document.getElementById('emailList');
|
|
const emailDetail = document.getElementById('emailDetail');
|
|
const sendEmailForm = document.getElementById('sendEmailForm');
|
|
const sendEmailResponse = document.getElementById('sendEmailResponse');
|
|
const FileReader = window.FileReader;
|
|
|
|
|
|
// CUSTOM GRAPH API QUERY
|
|
apiRequestForm.addEventListener('submit', async function(event) {
|
|
event.preventDefault();
|
|
|
|
const token = tokenInput.value;
|
|
const apiEndpoint = document.getElementById('apiEndpoint').value;
|
|
const httpMethod = document.getElementById('httpMethod').value;
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
// Check if POST or PUT method selected
|
|
let requestBody = null;
|
|
if (httpMethod === 'POST' || httpMethod === 'PUT') {
|
|
requestBody = document.getElementById('requestBody').value;
|
|
headers['Content-Type'] = 'application/json';
|
|
}
|
|
|
|
try {
|
|
const requestOptions = {
|
|
method: httpMethod,
|
|
headers
|
|
};
|
|
|
|
if (requestBody) {
|
|
requestOptions.body = requestBody;
|
|
}
|
|
|
|
const response = await fetch(apiEndpoint, requestOptions);
|
|
const data = await response.json();
|
|
|
|
apiResponse.textContent = JSON.stringify(data, null, 2);
|
|
} catch (error) {
|
|
apiResponse.textContent = 'Error: ' + error.message;
|
|
}
|
|
});
|
|
|
|
//MAIL - VIEWER
|
|
// Function to export emails to a CSV file
|
|
function exportEmailsToCSV(emails) {
|
|
const csvContent = [
|
|
'From,To,Subject,Date,Body'
|
|
];
|
|
|
|
emails.forEach(email => {
|
|
const from = email.from.emailAddress.name + ' (' + email.from.emailAddress.address + ')';
|
|
const to = email.toRecipients.map(recipient => recipient.emailAddress.address).join(', ');
|
|
const subject = email.subject;
|
|
const date = new Date(email.sentDateTime).toLocaleString();
|
|
const body = email.bodyPreview;
|
|
|
|
csvContent.push(`"${from}","${to}","${subject}","${date}","${body}"`);
|
|
});
|
|
|
|
const csvText = csvContent.join('\n');
|
|
const blob = new Blob([csvText], { type: 'text/csv' });
|
|
const a = document.createElement('a');
|
|
a.href = URL.createObjectURL(blob);
|
|
a.download = 'emails.csv';
|
|
a.click();
|
|
}
|
|
|
|
// Fetch and display emails
|
|
fetchEmailsButton.addEventListener('click', async function() {
|
|
const token = tokenInput.value;
|
|
const apiEndpoint = 'https://graph.microsoft.com/v1.0/me/mailFolders/inbox/messages';
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(apiEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
emailList.innerHTML = '';
|
|
data.value.forEach(email => {
|
|
const emailSummary = `
|
|
<div class="email-summary" data-id="${email.id}">
|
|
<strong>From:</strong> ${email.from.emailAddress.name} (${email.from.emailAddress.address})<br>
|
|
<strong>Subject:</strong> ${email.subject}<br>
|
|
<strong>Date:</strong> ${new Date(email.sentDateTime).toLocaleString()}<br>
|
|
<strong>Preview:</strong> ${email.bodyPreview}<br>
|
|
</div>
|
|
<hr>
|
|
`;
|
|
emailList.innerHTML += emailSummary;
|
|
});
|
|
|
|
// MAIL VIEWER - Event listener for email summaries
|
|
const emailSummaries = document.querySelectorAll('.email-summary');
|
|
emailSummaries.forEach(emailSummary => {
|
|
emailSummary.addEventListener('click', async () => {
|
|
const emailId = emailSummary.getAttribute('data-id');
|
|
const emailDetailEndpoint = `https://graph.microsoft.com/v1.0/me/messages/${emailId}`;
|
|
try {
|
|
const emailDetailResponse = await fetch(emailDetailEndpoint, { headers });
|
|
const emailDetailData = await emailDetailResponse.json();
|
|
|
|
emailDetail.innerHTML = `
|
|
<h3>Email Details</h3>
|
|
<strong>From:</strong> ${emailDetailData.from.emailAddress.name} (${emailDetailData.from.emailAddress.address})<br>
|
|
<strong>Subject:</strong> ${emailDetailData.subject}<br>
|
|
<strong>Date:</strong> ${new Date(emailDetailData.sentDateTime).toLocaleString()}<br>
|
|
<strong>Body:</strong> ${emailDetailData.body.content}
|
|
`;
|
|
} catch (error) {
|
|
emailDetail.innerHTML = `Error fetching email details: ${error.message}`;
|
|
}
|
|
});
|
|
});
|
|
// Store email data for exporting
|
|
window.emailsForExport = data.value;
|
|
} catch (error) {
|
|
emailList.innerHTML = `Error fetching emails: ${error.message}`;
|
|
}
|
|
|
|
});
|
|
|
|
// Export Emails
|
|
exportEmailsButton.addEventListener('click', function() {
|
|
if (window.emailsForExport) {
|
|
exportEmailsToCSV(window.emailsForExport);
|
|
} else {
|
|
alert('No email data available for export.');
|
|
}
|
|
});
|
|
|
|
|
|
// Search Emails
|
|
searchButton.addEventListener('click', async function() {
|
|
const token = tokenInput.value;
|
|
const searchInput = document.getElementById('searchInput').value.trim();
|
|
|
|
if (searchInput) {
|
|
const apiEndpoint = `https://graph.microsoft.com/v1.0/me/mailFolders/inbox/messages?$search="${searchInput}"`;
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(apiEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
// Store search results for exporting
|
|
window.emailsForExport = data.value;
|
|
|
|
// Call displayEmails with search results and headers
|
|
displayEmails(data.value, headers);
|
|
} catch (error) {
|
|
emailList.innerHTML = `Error searching emails: ${error.message}`;
|
|
}
|
|
} else {
|
|
alert('Please enter a search term.');
|
|
}
|
|
});
|
|
|
|
|
|
// Function to search display emails
|
|
function displayEmails(emails, headers) {
|
|
emailList.innerHTML = '';
|
|
|
|
emails.forEach(email => {
|
|
const emailSummary = `
|
|
<div class="email-summary" data-id="${email.id}">
|
|
<strong>From:</strong> ${email.from.emailAddress.name} (${email.from.emailAddress.address})<br>
|
|
<strong>Subject:</strong> ${email.subject}<br>
|
|
<strong>Date:</strong> ${new Date(email.sentDateTime).toLocaleString()}<br>
|
|
<strong>Preview:</strong> ${email.bodyPreview}<br>
|
|
</div>
|
|
`;
|
|
emailList.innerHTML += emailSummary;
|
|
});
|
|
|
|
// Add event listener for email summaries
|
|
const emailSummaries = document.querySelectorAll('.email-summary');
|
|
emailSummaries.forEach(emailSummary => {
|
|
emailSummary.addEventListener('click', async () => {
|
|
const emailId = emailSummary.getAttribute('data-id');
|
|
const emailDetailEndpoint = `https://graph.microsoft.com/v1.0/me/messages/${emailId}`;
|
|
try {
|
|
const emailDetailResponse = await fetch(emailDetailEndpoint, { headers });
|
|
const emailDetailData = await emailDetailResponse.json();
|
|
|
|
emailDetail.innerHTML = `
|
|
<h3>Email Details</h3>
|
|
<strong>From:</strong> ${emailDetailData.from.emailAddress.name} (${emailDetailData.from.emailAddress.address})<br>
|
|
<strong>Subject:</strong> ${emailDetailData.subject}<br>
|
|
<strong>Date:</strong> ${new Date(emailDetailData.sentDateTime).toLocaleString()}<br>
|
|
<strong>Body:</strong> ${emailDetailData.body.content}
|
|
`;
|
|
} catch (error) {
|
|
emailDetail.innerHTML = `Error fetching email details: ${error.message}`;
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
// LIST USERS
|
|
// Function to export users to a text file
|
|
function exportUsersToFile(users) {
|
|
const userText = users.join('\n');
|
|
|
|
const blob = new Blob([userText], { type: 'text/plain' });
|
|
const a = document.createElement('a');
|
|
a.href = URL.createObjectURL(blob);
|
|
a.download = 'users.txt';
|
|
a.click();
|
|
}
|
|
|
|
// List Users
|
|
listUsersButton.addEventListener('click', async function() {
|
|
const token = tokenInput.value;
|
|
|
|
try {
|
|
const allUsers = await fetchAllUsers(token);
|
|
|
|
// Display userPrincipalName fields only
|
|
const userPrincipalNames = allUsers.map(user => user.userPrincipalName);
|
|
listUsersResponse.textContent = userPrincipalNames.join('\n');
|
|
|
|
// Store userPrincipalNames for exporting
|
|
window.userPrincipalNamesForExport = userPrincipalNames;
|
|
} catch (error) {
|
|
listUsersResponse.textContent = 'Error: ' + error.message;
|
|
}
|
|
});
|
|
|
|
// Function to fetch all users using pagination
|
|
async function fetchAllUsers(token) {
|
|
const initialUrl = 'https://graph.microsoft.com/v1.0/users';
|
|
|
|
let allUsers = [];
|
|
|
|
let url = initialUrl;
|
|
|
|
while (url) {
|
|
const response = await fetch(url, {
|
|
headers: {
|
|
Authorization: `Bearer ${token}`
|
|
}
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (data.value) {
|
|
allUsers = allUsers.concat(data.value);
|
|
}
|
|
|
|
url = data['@odata.nextLink'];
|
|
}
|
|
|
|
return allUsers;
|
|
}
|
|
|
|
// Export Users
|
|
exportUsersButton.addEventListener('click', function() {
|
|
if (window.userPrincipalNamesForExport) {
|
|
exportUsersToFile(window.userPrincipalNamesForExport);
|
|
} else {
|
|
alert('No user data available for export.');
|
|
}
|
|
});
|
|
|
|
|
|
// DIRECTORY GROUPS
|
|
const groupApiEndpoint = 'https://graph.microsoft.com/v1.0/groups';
|
|
|
|
// Function to list groups
|
|
async function listGroups(token) {
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(groupApiEndpoint, { headers });
|
|
const data = await response.json();
|
|
return data.value;
|
|
} catch (error) {
|
|
console.error('Error listing groups:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Function to generate group list
|
|
function generateGroupList(parentNode, groups) {
|
|
const ul = document.createElement('ul');
|
|
parentNode.appendChild(ul);
|
|
|
|
groups.forEach(group => {
|
|
const li = document.createElement('li');
|
|
ul.appendChild(li);
|
|
|
|
const groupNode = document.createElement('div');
|
|
groupNode.classList.add('group-node');
|
|
groupNode.textContent = group.displayName;
|
|
li.appendChild(groupNode);
|
|
|
|
groupNode.addEventListener('click', async () => {
|
|
const members = await fetchGroupMembers(group.id, tokenInput.value);
|
|
showGroupMembers(members);
|
|
});
|
|
});
|
|
}
|
|
|
|
// Function to fetch group members
|
|
async function fetchGroupMembers(groupId, token) {
|
|
const membersApiEndpoint = `https://graph.microsoft.com/v1.0/groups/${groupId}/members`;
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(membersApiEndpoint, { headers });
|
|
const data = await response.json();
|
|
return data.value;
|
|
} catch (error) {
|
|
console.error('Error fetching group members:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
// Function to display group members
|
|
function showGroupMembers(members) {
|
|
const groupMembersContainer = document.getElementById('groupMembers');
|
|
groupMembersContainer.innerHTML = '';
|
|
|
|
const membersList = document.createElement('ul');
|
|
groupMembersContainer.appendChild(membersList);
|
|
|
|
members.forEach(member => {
|
|
const memberItem = document.createElement('li');
|
|
memberItem.innerHTML = `<strong>Name:</strong> ${member.displayName}<br><strong>Email:</strong> ${member.userPrincipalName}<br><strong>ID:</strong> ${member.id}`;
|
|
membersList.appendChild(memberItem);
|
|
});
|
|
}
|
|
|
|
// List Groups button click event
|
|
const listGroupsButton = document.getElementById('listGroupsButton');
|
|
const groupList = document.getElementById('groupList');
|
|
|
|
listGroupsButton.addEventListener('click', async () => {
|
|
groupList.innerHTML = ''; // Clear existing content
|
|
const groups = await listGroups(tokenInput.value); // Replace with your token retrieval logic
|
|
generateGroupList(groupList, groups);
|
|
});
|
|
|
|
|
|
function exportGroupMembersToCSV(members) {
|
|
// Create CSV content
|
|
let csvContent = "ID,Name,Email\n";
|
|
members.forEach(member => {
|
|
csvContent += `${member.id},${member.displayName},${member.userPrincipalName}\n`;
|
|
});
|
|
|
|
// Create a Blob containing the CSV content
|
|
const blob = new Blob([csvContent], { type: 'text/csv' });
|
|
|
|
// Create a download link for the Blob
|
|
const downloadLink = document.createElement('a');
|
|
downloadLink.href = URL.createObjectURL(blob);
|
|
downloadLink.download = 'group_members.csv';
|
|
downloadLink.click();
|
|
|
|
// Revoke the object URL to free up resources
|
|
URL.revokeObjectURL(downloadLink.href);
|
|
}
|
|
|
|
// Attach export button click event
|
|
const exportButton = document.getElementById('exportButton');
|
|
exportButton.addEventListener('click', async function () {
|
|
const displayedGroupMembers = await fetchDisplayedGroupMembers();
|
|
if (displayedGroupMembers.length > 0) {
|
|
exportGroupMembersToCSV(displayedGroupMembers);
|
|
} else {
|
|
alert('No group members data available for export.');
|
|
}
|
|
});
|
|
|
|
// Function to fetch the currently displayed group's members
|
|
async function fetchDisplayedGroupMembers() {
|
|
const groupMembersContainer = document.getElementById('groupMembers');
|
|
const memberItems = groupMembersContainer.getElementsByTagName('li');
|
|
const token = tokenInput.value;
|
|
|
|
const members = [];
|
|
for (const memberItem of memberItems) {
|
|
const name = memberItem.querySelector('strong:nth-child(1)').textContent.split(':')[1].trim();
|
|
const email = memberItem.querySelector('strong:nth-child(2)').textContent.split(':')[1].trim();
|
|
const id = memberItem.querySelector('strong:nth-child(3)').textContent.split(':')[1].trim();
|
|
|
|
members.push({ id, displayName: name, userPrincipalName: email });
|
|
}
|
|
|
|
return members;
|
|
}
|
|
|
|
|
|
|
|
// MAIL - CUSTOM EMAIL VIEWER
|
|
const customEmailViewerForm = document.getElementById('customEmailViewerForm');
|
|
const customEmailList = document.getElementById('customEmailList');
|
|
const customEmailDetail = document.getElementById('customEmailDetail');
|
|
|
|
customEmailViewerForm.addEventListener('submit', async function(event) {
|
|
event.preventDefault();
|
|
|
|
const token = tokenInput.value;
|
|
const customUserId = document.getElementById('customUserId').value;
|
|
const customFolder = document.getElementById('customFolder').value;
|
|
|
|
const customApiEndpoint = `https://graph.microsoft.com/v1.0/users/${customUserId}/mailFolders/${customFolder}/messages`;
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(customApiEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
customEmailList.innerHTML = '';
|
|
data.value.forEach(email => {
|
|
const customEmailSummary = `
|
|
<div class="email-summary" data-id="${email.id}">
|
|
<strong>From:</strong> ${email.sender ? `${email.sender.emailAddress.name} (${email.sender.emailAddress.address})` : 'Unknown'}<br>
|
|
<strong>Subject:</strong> ${email.subject}<br>
|
|
<strong>Date:</strong> ${new Date(email.sentDateTime).toLocaleString()}<br>
|
|
<strong>Preview:</strong> ${email.bodyPreview}<br>
|
|
</div>
|
|
<hr>
|
|
`;
|
|
customEmailList.innerHTML += customEmailSummary;
|
|
});
|
|
|
|
// MAIL - CUSTOM EMAIL VIEWER - Add event listener to custom email summaries
|
|
const customEmailSummaries = document.querySelectorAll('.email-summary');
|
|
customEmailSummaries.forEach(customEmailSummary => {
|
|
customEmailSummary.addEventListener('click', async () => {
|
|
const customEmailId = customEmailSummary.getAttribute('data-id');
|
|
const customEmailDetailEndpoint = `https://graph.microsoft.com/v1.0/users/${customUserId}/messages/${customEmailId}`;
|
|
try {
|
|
const customEmailDetailResponse = await fetch(customEmailDetailEndpoint, { headers });
|
|
const customEmailDetailData = await customEmailDetailResponse.json();
|
|
|
|
customEmailDetail.innerHTML = `
|
|
<h3>Email Details</h3>
|
|
<strong>From:</strong> ${customEmailDetailData.sender ? `${customEmailDetailData.sender.emailAddress.name} (${customEmailDetailData.sender.emailAddress.address})` : 'Unknown'}<br>
|
|
<strong>Subject:</strong> ${customEmailDetailData.subject}<br>
|
|
<strong>Date:</strong> ${new Date(customEmailDetailData.sentDateTime).toLocaleString()}<br>
|
|
<strong>Body:</strong> ${customEmailDetailData.body.content}
|
|
`;
|
|
} catch (error) {
|
|
customEmailDetail.innerHTML = `Error fetching email details: ${error.message}`;
|
|
}
|
|
});
|
|
});
|
|
} catch (error) {
|
|
customEmailList.innerHTML = `Error fetching emails: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
// MAIL SEND - Form
|
|
sendEmailForm.addEventListener('submit', async function(event) {
|
|
event.preventDefault();
|
|
|
|
const token = tokenInput.value;
|
|
const to = document.getElementById('to').value;
|
|
const subject = document.getElementById('subject').value;
|
|
const body = document.getElementById('body').value;
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
};
|
|
|
|
// MAIL SEND - Attachments
|
|
const attachmentsInput = document.getElementById('attachments');
|
|
const attachments = attachmentsInput.files;
|
|
|
|
const emailMessage = {
|
|
message: {
|
|
subject,
|
|
body: {
|
|
contentType: 'Text',
|
|
content: body
|
|
},
|
|
toRecipients: [
|
|
{
|
|
emailAddress: {
|
|
address: to
|
|
}
|
|
}
|
|
],
|
|
attachments: [] // Initialize an empty array for attachments
|
|
},
|
|
saveToSentItems: false
|
|
};
|
|
|
|
for (const attachment of attachments) {
|
|
const attachmentPayload = {
|
|
'@odata.type': '#microsoft.graph.fileAttachment',
|
|
contentBytes: '',
|
|
contentType: attachment.type,
|
|
name: attachment.name
|
|
};
|
|
|
|
// Read the attachment content as base64 and assign it to the payload
|
|
const attachmentContent = await readFileAsBase64(attachment);
|
|
attachmentPayload.contentBytes = attachmentContent;
|
|
|
|
emailMessage.message.attachments.push(attachmentPayload);
|
|
}
|
|
|
|
try {
|
|
// MAIL SEND - Use fetch to send the email and handle the response
|
|
const sendEmailResponse = await fetch('https://graph.microsoft.com/v1.0/me/sendMail', {
|
|
method: 'POST',
|
|
headers,
|
|
body: JSON.stringify(emailMessage)
|
|
});
|
|
|
|
if (sendEmailResponse.status === 202) {
|
|
sendEmailResponse.textContent = 'Message Sent Successfully. It is being processed.';
|
|
} else {
|
|
sendEmailResponse.textContent = 'Error sending email: Unexpected response.';
|
|
}
|
|
} catch (error) {
|
|
sendEmailResponse.textContent = `Error sending email: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
|
|
// TEAMS -Event listener for the "Fetch Teams Chats" button
|
|
const fetchChatsButton = document.getElementById('fetchChatsButton');
|
|
fetchChatsButton.addEventListener('click', listChats);
|
|
|
|
// TEAMS - Function to fetch and display list of chats
|
|
async function listChats() {
|
|
const token = tokenInput.value;
|
|
const apiEndpoint = 'https://graph.microsoft.com/v1.0/me/chats';
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(apiEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
const chatList = document.getElementById('chatList');
|
|
chatList.innerHTML = '';
|
|
|
|
data.value.forEach(chat => {
|
|
const chatSummary = `
|
|
<div class="chat-summary" data-id="${chat.id}">
|
|
<strong>Teams Chat Conversation:</strong> ${chat.lastUpdatedDateTime}
|
|
</div>
|
|
`;
|
|
chatList.innerHTML += chatSummary;
|
|
});
|
|
|
|
// Add event listener to chat summaries
|
|
const chatSummaries = document.querySelectorAll('.chat-summary');
|
|
chatSummaries.forEach(chatSummary => {
|
|
chatSummary.addEventListener('click', async () => {
|
|
const chatId = chatSummary.getAttribute('data-id');
|
|
await fetchAndDisplayChatMessages(chatId, headers);
|
|
// Update chat ID for sending messages
|
|
sendMessageButton.setAttribute('data-chat-id', chatId);
|
|
});
|
|
});
|
|
} catch (error) {
|
|
chatList.innerHTML = `Error fetching chats: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
// TEAMS - Function to fetch and display chat messages
|
|
async function fetchAndDisplayChatMessages(chatId, headers) {
|
|
const chatMessagesEndpoint = `https://graph.microsoft.com/v1.0/me/chats/${chatId}/messages`;
|
|
|
|
try {
|
|
const response = await fetch(chatMessagesEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
const chatMessages = document.getElementById('chatMessages');
|
|
chatMessages.innerHTML = '';
|
|
|
|
// Reverse the order of messages to display the latest message at the bottom
|
|
const reversedMessages = data.value.reverse();
|
|
|
|
for (const message of reversedMessages) {
|
|
const senderDisplayName = message.from && message.from.user && message.from.user.displayName ? message.from.user.displayName : "Unknown User";
|
|
const senderUserId = message.from && message.from.user && message.from.user.id ? message.from.user.id : "Unknown ID";
|
|
const createdDateTime = new Date(message.createdDateTime).toLocaleString();
|
|
|
|
let messageContent = '';
|
|
|
|
if (message.body && message.body.contentType === 'html') {
|
|
messageContent = message.body.content;
|
|
const imageUrls = extractImageUrls(messageContent);
|
|
|
|
// Display extracted images
|
|
for (const imageUrl of imageUrls) {
|
|
const imageData = await fetch(imageUrl, { headers });
|
|
if (imageData.ok) {
|
|
const imageBlob = await imageData.blob();
|
|
const imageUrlObject = URL.createObjectURL(imageBlob);
|
|
messageContent += `<br><img src="${imageUrlObject}" alt="Image" style="max-width: 100%; height: auto;"><br>`;
|
|
}
|
|
}
|
|
} else if (message.body && message.body.content) {
|
|
messageContent = message.body.content;
|
|
}
|
|
|
|
const attachments = message.attachments || [];
|
|
attachments.forEach(attachment => {
|
|
if (attachment.contentType === 'image/png' || attachment.contentType === 'image/jpeg') {
|
|
// Display image attachment
|
|
const imageSrc = attachment.contentUrl;
|
|
messageContent += `<br><img class="message-image" src="${imageSrc}" alt="Attachment">`;
|
|
} else {
|
|
// Display other file attachment
|
|
const fileSrc = attachment.contentUrl;
|
|
const fileName = attachment.name;
|
|
messageContent += `<br><a href="${fileSrc}" target="_blank">${fileName}</a>`;
|
|
}
|
|
});
|
|
|
|
const messageDetail = `
|
|
<div class="message">
|
|
<div class="message-header">
|
|
<strong>${senderDisplayName} (${senderUserId})</strong> - ${createdDateTime}
|
|
</div>
|
|
<div class="message-content">
|
|
${messageContent}
|
|
</div>
|
|
</div>
|
|
<hr>
|
|
`;
|
|
chatMessages.innerHTML += messageDetail;
|
|
}
|
|
} catch (error) {
|
|
chatMessages.innerHTML = `Error fetching chat messages: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
function extractImageUrls(htmlContent) {
|
|
const imageUrls = [];
|
|
const imageRegex = /<img[^>]+src="([^">]+)"/g;
|
|
let match = imageRegex.exec(htmlContent);
|
|
while (match !== null) {
|
|
imageUrls.push(match[1]);
|
|
match = imageRegex.exec(htmlContent);
|
|
}
|
|
return imageUrls;
|
|
}
|
|
|
|
// TEAMS - Send Message Functionality
|
|
const sendMessageButton = document.getElementById('sendMessageButton');
|
|
const messageTextBox = document.getElementById('messageTextBox');
|
|
|
|
sendMessageButton.addEventListener('click', async () => {
|
|
const message = messageTextBox.value;
|
|
if (message) {
|
|
const chatId = sendMessageButton.getAttribute('data-chat-id');
|
|
await sendMessageToChat(chatId, message);
|
|
}
|
|
});
|
|
|
|
// TEAMS - SEND
|
|
async function sendMessageToChat(chatId, message) {
|
|
const token = tokenInput.value;
|
|
const sendMessageUrl = `https://graph.microsoft.com/v1.0/me/chats/${chatId}/messages`;
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`,
|
|
'Content-Type': 'application/json'
|
|
};
|
|
|
|
const messagePayload = {
|
|
body: {
|
|
content: message
|
|
}
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(sendMessageUrl, {
|
|
method: 'POST',
|
|
headers,
|
|
body: JSON.stringify(messagePayload)
|
|
});
|
|
|
|
if (response.status === 201) {
|
|
// Message sent successfully
|
|
console.log('Message sent successfully');
|
|
} else {
|
|
// Handle error response
|
|
console.error('Error sending message:', response.statusText);
|
|
}
|
|
} catch (error) {
|
|
console.error('Error sending message:', error.message);
|
|
}
|
|
}
|
|
|
|
|
|
// TEAMS - PUBLIC Add event listener for listing public Teams chats
|
|
const listPublicChatsButton = document.getElementById('listPublicChatsButton');
|
|
listPublicChatsButton.addEventListener('click', listPublicChats);
|
|
|
|
// TEAMS - PUBLIC Function to fetch and display public Teams chats
|
|
async function listPublicChats() {
|
|
const token = tokenInput.value;
|
|
const apiEndpoint = 'https://graph.microsoft.com/v1.0/me/joinedTeams';
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(apiEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
const publicChatList = document.getElementById('publicChatList');
|
|
publicChatList.innerHTML = '';
|
|
|
|
data.value.forEach(async team => {
|
|
const teamChatsEndpoint = `https://graph.microsoft.com/v1.0/teams/${team.id}/channels`;
|
|
|
|
try {
|
|
const chatsResponse = await fetch(teamChatsEndpoint, { headers });
|
|
const chatsData = await chatsResponse.json();
|
|
|
|
chatsData.value.forEach(chat => {
|
|
if (chat.displayName) {
|
|
const chatSummary = `
|
|
<div class="public-chat-summary" data-id="${chat.id}">
|
|
<strong>Public Chat Name:</strong> ${chat.displayName}<br>
|
|
<strong>Description:</strong> ${chat.description || 'No description available'}<br>
|
|
</div>
|
|
<hr>
|
|
`;
|
|
publicChatList.innerHTML += chatSummary;
|
|
}
|
|
});
|
|
} catch (error) {
|
|
publicChatList.innerHTML = `Error fetching chats: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
// Add event listener to public chat summaries
|
|
const publicChatSummaries = document.querySelectorAll('.public-chat-summary');
|
|
publicChatSummaries.forEach(chatSummary => {
|
|
chatSummary.addEventListener('click', async () => {
|
|
const chatId = chatSummary.getAttribute('data-id');
|
|
await fetchAndDisplayPublicChatMessages(chatId, headers);
|
|
// Update chat ID for sending messages
|
|
sendMessageButton.setAttribute('data-chat-id', chatId);
|
|
});
|
|
});
|
|
} catch (error) {
|
|
publicChatList.innerHTML = `Error fetching public chats: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
// TEAMS - PUBLIC Function to fetch and display chat messages
|
|
async function fetchAndDisplayPublicChatMessages(chatId, headers) {
|
|
const chatMessagesEndpoint = `https://graph.microsoft.com/v1.0/teams/${chatId}/messages`;
|
|
|
|
try {
|
|
const response = await fetch(chatMessagesEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
const publicChatMessages = document.getElementById('publicChatMessages');
|
|
publicChatMessages.innerHTML = '';
|
|
|
|
data.value.forEach(message => {
|
|
const senderDisplayName = message.from && message.from.user && message.from.user.displayName ? message.from.user.displayName : "Unknown User";
|
|
const messageContent = message.body && message.body.content ? message.body.content : "No content available";
|
|
const createdDateTime = new Date(message.createdDateTime).toLocaleString();
|
|
|
|
const messageDetail = `
|
|
<div>
|
|
<strong>From:</strong> ${senderDisplayName}<br>
|
|
<strong>Message:</strong> ${messageContent}<br>
|
|
<strong>Created:</strong> ${createdDateTime}<br>
|
|
</div>
|
|
<hr>
|
|
`;
|
|
publicChatMessages.innerHTML += messageDetail;
|
|
});
|
|
} catch (error) {
|
|
publicChatMessages.innerHTML = `Error fetching chat messages: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
// ONEDRIVE - List Files
|
|
const listFilesButton = document.getElementById('listFilesButton');
|
|
const fileList = document.getElementById('fileList');
|
|
|
|
listFilesButton.addEventListener('click', async function () {
|
|
const token = tokenInput.value;
|
|
const apiEndpoint = 'https://graph.microsoft.com/v1.0/me/drive/root/children';
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(apiEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
fileList.innerHTML = '';
|
|
|
|
data.value.forEach(file => {
|
|
const fileCard = document.createElement('div');
|
|
fileCard.classList.add('file-card');
|
|
|
|
const fileName = document.createElement('div');
|
|
fileName.classList.add('file-name');
|
|
fileName.textContent = file.name;
|
|
fileCard.appendChild(fileName);
|
|
|
|
const fileDetails = document.createElement('div');
|
|
fileDetails.classList.add('file-details');
|
|
fileDetails.innerHTML = `
|
|
<p>Size: ${file.size ? `${file.size} bytes` : 'N/A'}</p>
|
|
<p>Type: ${file.file ? 'File' : 'Folder'}</p>
|
|
<a href="#" class="${file.file ? 'download-link' : 'folder-link'}" data-id="${file.id}">
|
|
${file.file ? 'Download' : 'Open Folder'}
|
|
</a>
|
|
`;
|
|
fileCard.appendChild(fileDetails);
|
|
|
|
fileList.appendChild(fileCard);
|
|
|
|
const link = fileDetails.querySelector('.download-link, .folder-link');
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const itemId = link.getAttribute('data-id');
|
|
if (file.file) {
|
|
await downloadFile(itemId, headers);
|
|
} else {
|
|
await fetchAndDisplayFolderContents(itemId, headers);
|
|
}
|
|
});
|
|
});
|
|
} catch (error) {
|
|
fileList.innerHTML = `Error fetching files and folders: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
|
|
// ONEDRIVE - Function to download a file
|
|
async function downloadFile(fileId, headers) {
|
|
// Construct the download URL
|
|
const downloadUrl = `https://graph.microsoft.com/v1.0/me/drive/items/${fileId}/content`;
|
|
|
|
try {
|
|
const response = await fetch(downloadUrl, { headers });
|
|
const blob = await response.blob();
|
|
|
|
// Create a temporary anchor element to initiate download
|
|
const a = document.createElement('a');
|
|
a.href = URL.createObjectURL(blob);
|
|
a.download = fileId;
|
|
a.click();
|
|
} catch (error) {
|
|
fileList.innerHTML = `Error downloading file: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
// ONEDRIVE - Function to fetch and display folder contents
|
|
async function fetchAndDisplayFolderContents(folderId, headers) {
|
|
const folderContentsUrl = `https://graph.microsoft.com/v1.0/me/drive/items/${folderId}/children`;
|
|
|
|
try {
|
|
const response = await fetch(folderContentsUrl, { headers });
|
|
const data = await response.json();
|
|
|
|
fileList.innerHTML = '';
|
|
data.value.forEach(item => {
|
|
const fileCard = document.createElement('div');
|
|
fileCard.classList.add('file-card');
|
|
|
|
const itemName = document.createElement('div');
|
|
itemName.classList.add('item-name');
|
|
itemName.textContent = item.name;
|
|
fileCard.appendChild(itemName);
|
|
|
|
const itemDetails = document.createElement('div');
|
|
itemDetails.classList.add('item-details');
|
|
itemDetails.innerHTML = `
|
|
<p>Size: ${item.size ? `${item.size} bytes` : 'N/A'}</p>
|
|
<p>Type: ${item.file ? 'File' : 'Folder'}</p>
|
|
<a href="#" class="${item.file ? 'download-link' : 'folder-link'}" data-id="${item.id}">
|
|
${item.file ? 'Download' : 'Open Folder'}
|
|
</a>
|
|
`;
|
|
fileCard.appendChild(itemDetails);
|
|
|
|
fileList.appendChild(fileCard);
|
|
|
|
const link = itemDetails.querySelector('.download-link, .folder-link');
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const itemId = link.getAttribute('data-id');
|
|
if (item.file) {
|
|
await downloadFile(itemId, headers);
|
|
} else {
|
|
await fetchAndDisplayFolderContents(itemId, headers);
|
|
}
|
|
});
|
|
});
|
|
} catch (error) {
|
|
fileList.innerHTML = `Error fetching folder contents: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
// ONEDRIVE SHARED FILES
|
|
const listSharedFilesButton = document.getElementById('listSharedFilesButton');
|
|
const sharedFileList = document.getElementById('sharedFileList');
|
|
|
|
listSharedFilesButton.addEventListener('click', async function () {
|
|
const token = tokenInput.value;
|
|
const sharedFilesEndpoint = 'https://graph.microsoft.com/v1.0/me/drive/sharedWithMe';
|
|
|
|
const headers = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(sharedFilesEndpoint, { headers });
|
|
const data = await response.json();
|
|
|
|
sharedFileList.innerHTML = '';
|
|
|
|
data.value.forEach(file => {
|
|
const fileCard = document.createElement('div');
|
|
fileCard.classList.add('file-card');
|
|
|
|
const fileName = document.createElement('div');
|
|
fileName.classList.add('file-name');
|
|
fileName.textContent = file.name;
|
|
fileCard.appendChild(fileName);
|
|
|
|
const fileDetails = document.createElement('div');
|
|
fileDetails.classList.add('file-details');
|
|
fileDetails.innerHTML = `
|
|
<p>Size: ${file.size ? `${file.size} bytes` : 'N/A'}</p>
|
|
<p>Type: ${file.file ? 'File' : 'Folder'}</p>
|
|
${file.file ? `<a href="#" class="download-link" data-id="${file.id}">Download</a>` : ''}
|
|
`;
|
|
fileCard.appendChild(fileDetails);
|
|
|
|
sharedFileList.appendChild(fileCard);
|
|
|
|
if (file.file) {
|
|
const downloadLink = fileDetails.querySelector('.download-link');
|
|
downloadLink.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const itemId = downloadLink.getAttribute('data-id');
|
|
await downloadFile(itemId, headers);
|
|
});
|
|
}
|
|
});
|
|
} catch (error) {
|
|
sharedFileList.innerHTML = `Error fetching shared files: ${error.message}`;
|
|
}
|
|
});
|
|
|
|
|
|
// SHAREPOINT
|
|
const listDrivesButton = document.getElementById('listDrivesButton');
|
|
listDrivesButton.addEventListener('click', listSharePointDrives);
|
|
const listSitesButton = document.getElementById('listSitesButton');
|
|
listSitesButton.addEventListener('click', listSharePointSites);
|
|
|
|
|
|
async function listSharePointDrives() {
|
|
const token = tokenInput.value;
|
|
|
|
// Step 1: Get the root SharePoint site
|
|
const siteApiEndpoint = 'https://graph.microsoft.com/v1.0/sites/root';
|
|
|
|
const siteHeaders = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const siteResponse = await fetch(siteApiEndpoint, { headers: siteHeaders });
|
|
const siteData = await siteResponse.json();
|
|
|
|
const siteId = siteData.id;
|
|
|
|
// Step 2: Get drives associated with the root SharePoint site
|
|
const drivesApiEndpoint = `https://graph.microsoft.com/v1.0/sites/${siteId}/drives`;
|
|
|
|
const drivesHeaders = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
const drivesResponse = await fetch(drivesApiEndpoint, { headers: drivesHeaders });
|
|
const drivesData = await drivesResponse.json();
|
|
|
|
const driveList = document.getElementById('driveList');
|
|
driveList.innerHTML = '';
|
|
|
|
drivesData.value.forEach(drive => {
|
|
const driveSummary = `
|
|
<div class="sharepoint-drive-summary" data-drive-id="${drive.id}">
|
|
<strong>Drive Name:</strong> ${drive.name}<br>
|
|
<strong>Drive Type:</strong> ${drive.driveType}<br>
|
|
<strong>Drive ID:</strong> ${drive.id}<br>
|
|
</div>
|
|
<hr>
|
|
`;
|
|
driveList.innerHTML += driveSummary;
|
|
});
|
|
|
|
const driveSummaries = document.querySelectorAll('.sharepoint-drive-summary');
|
|
driveSummaries.forEach(driveSummary => {
|
|
driveSummary.addEventListener('click', async () => {
|
|
const driveId = driveSummary.getAttribute('data-drive-id');
|
|
await listDriveContents(driveId, token);
|
|
});
|
|
});
|
|
} catch (error) {
|
|
driveList.innerHTML = `Error fetching SharePoint drives: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
async function listDriveContents(driveId, token) {
|
|
const driveContentsApiEndpoint = `https://graph.microsoft.com/v1.0/drives/${driveId}/root/children`;
|
|
|
|
const driveContentsHeaders = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const driveContentsResponse = await fetch(driveContentsApiEndpoint, { headers: driveContentsHeaders });
|
|
const driveContentsData = await driveContentsResponse.json();
|
|
|
|
const sharePointDriveFileListContainer = document.getElementById('sharePointDriveFileList');
|
|
sharePointDriveFileListContainer.innerHTML = '';
|
|
|
|
driveContentsData.value.forEach(item => {
|
|
const itemSummary = `
|
|
<div class="sharepoint-item-summary" data-item-id="${item.id}" data-item-type="${item.folder ? 'folder' : 'file'}">
|
|
<strong>Name:</strong> ${item.name}<br>
|
|
<strong>Size:</strong> ${item.size ? `${item.size} bytes` : 'N/A'}<br>
|
|
<strong>Type:</strong> ${item.folder ? 'Folder' : 'File'}<br>
|
|
${item.folder ? `<a href="#" class="folder-link" data-folder-id="${item.id}">Open Folder</a>` : `<a href="${item['@microsoft.graph.downloadUrl']}" class="sharepoint-download-link">Download</a>`}
|
|
</div>
|
|
<hr>
|
|
`;
|
|
sharePointDriveFileListContainer.innerHTML += itemSummary;
|
|
});
|
|
|
|
// Event listener to file links
|
|
const sharePointDownloadLinks = document.querySelectorAll('.sharepoint-download-link');
|
|
sharePointDownloadLinks.forEach(link => {
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const downloadUrl = link.getAttribute('href');
|
|
await downloadSharePointFile(downloadUrl);
|
|
});
|
|
});
|
|
|
|
const spfolderLinks = document.querySelectorAll('.folder-link');
|
|
spfolderLinks.forEach(link => {
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const folderId = link.getAttribute('data-folder-id');
|
|
await fetchAndDisplaySharePointDriveContents(driveId, folderId, token, sharePointDriveFileListContainer); // Pass sharePointDriveFileListContainer
|
|
});
|
|
});
|
|
} catch (error) {
|
|
sharePointDriveFileListContainer.innerHTML = `Error fetching drive contents: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
|
|
async function listSharePointSites() {
|
|
const token = tokenInput.value;
|
|
|
|
// Step 1: Search for all SharePoint sites
|
|
const sitesApiEndpoint = 'https://graph.microsoft.com/v1.0/sites?search=*';
|
|
|
|
const sitesHeaders = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const sitesResponse = await fetch(sitesApiEndpoint, { headers: sitesHeaders });
|
|
const sitesData = await sitesResponse.json();
|
|
|
|
const siteList = document.getElementById('siteList');
|
|
siteList.innerHTML = '';
|
|
|
|
sitesData.value.forEach(site => {
|
|
const siteSummary = `
|
|
<div class="sharepoint-site-summary" data-site-id="${site.id}">
|
|
<strong>Display Name:</strong> ${site.displayName}<br>
|
|
<strong>Name:</strong> ${site.name}<br>
|
|
<strong>URL:</strong> ${site.webUrl}<br>
|
|
</div>
|
|
<hr>
|
|
`;
|
|
siteList.innerHTML += siteSummary;
|
|
});
|
|
|
|
const siteSummaries = document.querySelectorAll('.sharepoint-site-summary');
|
|
siteSummaries.forEach(siteSummary => {
|
|
siteSummary.addEventListener('click', async () => {
|
|
const siteId = siteSummary.getAttribute('data-site-id');
|
|
await listSiteContents(siteId, token);
|
|
});
|
|
});
|
|
} catch (error) {
|
|
siteList.innerHTML = `Error fetching SharePoint sites: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
async function listSiteContents(driveId, token) {
|
|
const driveContentsApiEndpoint = `https://graph.microsoft.com/v1.0/sites/${driveId}/drive/root/children`;
|
|
|
|
const driveContentsHeaders = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const driveContentsResponse = await fetch(driveContentsApiEndpoint, { headers: driveContentsHeaders });
|
|
const driveContentsData = await driveContentsResponse.json();
|
|
|
|
const sharePointfileListContainer = document.getElementById('sharePointfileList');
|
|
sharePointfileListContainer.innerHTML = '';
|
|
|
|
driveContentsData.value.forEach(item => {
|
|
const itemSummary = `
|
|
<div class="sharepoint-item-summary" data-item-id="${item.id}" data-item-type="${item.folder ? 'folder' : 'file'}">
|
|
<strong>Name:</strong> ${item.name}<br>
|
|
<strong>Size:</strong> ${item.size ? `${item.size} bytes` : 'N/A'}<br>
|
|
<strong>Type:</strong> ${item.folder ? 'Folder' : 'File'}<br>
|
|
${item.folder ? `<a href="#" class="folder-link" data-folder-id="${item.id}">Open Folder</a>` : `<a href="${item['@microsoft.graph.downloadUrl']}" class="sharepoint-download-link">Download</a>`}
|
|
</div>
|
|
<hr>
|
|
`;
|
|
sharePointfileListContainer.innerHTML += itemSummary;
|
|
});
|
|
|
|
// Event listener to file links
|
|
const sharePointDownloadLinks = document.querySelectorAll('.sharepoint-download-link');
|
|
sharePointDownloadLinks.forEach(link => {
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const downloadUrl = link.getAttribute('href');
|
|
await downloadSharePointFile(downloadUrl);
|
|
});
|
|
});
|
|
|
|
const spfolderLinks = document.querySelectorAll('.folder-link');
|
|
spfolderLinks.forEach(link => {
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const folderId = link.getAttribute('data-folder-id');
|
|
await fetchAndDisplaySharePointFolderContents(driveId, folderId, token, sharePointfileListContainer); // Pass sharePointfileListContainer
|
|
});
|
|
});
|
|
} catch (error) {
|
|
sharePointfileListContainer.innerHTML = `Error fetching drive contents: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
// Function to fetch and display folder contents within SharePoint drive
|
|
|
|
async function fetchAndDisplaySharePointDriveContents(driveId, folderId, token, container) {
|
|
const folderContentsUrl = `https://graph.microsoft.com/v1.0/drives/${driveId}/items/${folderId}/children`;
|
|
|
|
const folderContentsHeaders = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(folderContentsUrl, { headers: folderContentsHeaders });
|
|
const data = await response.json();
|
|
|
|
const sharePointDriveFileListContainer = document.getElementById('sharePointDriveFileList');
|
|
data.value.forEach(item => {
|
|
const itemSummary = `
|
|
<div class="item-summary" data-item-id="${item.id}" data-item-type="${item.folder ? 'folder' : 'file'}">
|
|
<strong>Name:</strong> ${item.name}<br>
|
|
<strong>Size:</strong> ${item.size ? `${item.size} bytes` : 'N/A'}<br>
|
|
<strong>Type:</strong> ${item.folder ? 'Folder' : 'File'}<br>
|
|
${item.folder ? `<a href="#" class="folder-link" data-folder-id="${item.id}" onclick="openSharePointFolder(event, '${driveId}', '${item.id}', token)">Open Folder</a>` : `<a href="${item['@microsoft.graph.downloadUrl']}" class="sharepoint-download-link">Download</a>`}
|
|
</div>
|
|
<hr>
|
|
`;
|
|
sharePointDriveFileListContainer.innerHTML += itemSummary;
|
|
});
|
|
|
|
// Event listener to folder links
|
|
const spFolderLinks = document.querySelectorAll('.folder-link');
|
|
spFolderLinks.forEach(link => {
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const driveId = link.parentElement.getAttribute('data-drive-id');
|
|
const folderId = link.getAttribute('data-folder-id');
|
|
await fetchAndDisplaySharePointFolderContents(driveId, folderId, token);
|
|
});
|
|
});
|
|
} catch (error) {
|
|
container.innerHTML = `Error fetching folder contents: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
|
|
async function fetchAndDisplaySharePointFolderContents(driveId, folderId, token, container) {
|
|
const folderContentsUrl = `https://graph.microsoft.com/v1.0/sites/${driveId}/drive/items/${folderId}/children`;
|
|
|
|
const folderContentsHeaders = {
|
|
'Authorization': `Bearer ${token}`
|
|
};
|
|
|
|
try {
|
|
const response = await fetch(folderContentsUrl, { headers: folderContentsHeaders });
|
|
const data = await response.json();
|
|
|
|
const sharePointfileListContainer = document.getElementById('sharePointfileList');
|
|
data.value.forEach(item => {
|
|
const itemSummary = `
|
|
<div class="item-summary" data-item-id="${item.id}" data-item-type="${item.folder ? 'folder' : 'file'}">
|
|
<strong>Name:</strong> ${item.name}<br>
|
|
<strong>Size:</strong> ${item.size ? `${item.size} bytes` : 'N/A'}<br>
|
|
<strong>Type:</strong> ${item.folder ? 'Folder' : 'File'}<br>
|
|
${item.folder ? `<a href="#" class="folder-link" data-folder-id="${item.id}" onclick="fetchAndDisplaySharePointFolderContents('${driveId}', '${item.id}', '${token}')">Open Folder</a>` : `<a href="${item['@microsoft.graph.downloadUrl']}" class="sharepoint-download-link">Download</a>`}
|
|
</div>
|
|
<hr>
|
|
`;
|
|
sharePointfileListContainer.innerHTML += itemSummary;
|
|
});
|
|
|
|
// Event listener to folder links
|
|
const spFolderLinks = document.querySelectorAll('.folder-link');
|
|
spFolderLinks.forEach(link => {
|
|
link.addEventListener('click', async (event) => {
|
|
event.preventDefault();
|
|
const driveId = link.parentElement.getAttribute('data-drive-id');
|
|
const folderId = link.getAttribute('data-folder-id');
|
|
await fetchAndDisplaySharePointFolderContents(driveId, folderId, token);
|
|
});
|
|
});
|
|
} catch (error) {
|
|
container.innerHTML = `Error fetching folder contents: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
async function downloadSharePointFile(downloadUrl) {
|
|
try {
|
|
const response = await fetch(downloadUrl);
|
|
const blob = await response.blob();
|
|
|
|
const a = document.createElement('a');
|
|
a.href = URL.createObjectURL(blob);
|
|
a.download = 'downloadedFile';
|
|
a.click();
|
|
} catch (error) {
|
|
sharePointfileList.innerHTML = `Error downloading file: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
function openSharePointFolder(driveId, folderId, token) {
|
|
fetchAndDisplaySharePointFolderContents(driveId, folderId, token);
|
|
}
|
|
|
|
|
|
// Function to read a file and convert it to base64
|
|
function readFileAsBase64(file) {
|
|
return new Promise((resolve, reject) => {
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
resolve(reader.result.split(',')[1]); // Extract base64 content from data URL
|
|
};
|
|
reader.onerror = reject;
|
|
reader.readAsDataURL(file);
|
|
});
|
|
}
|
|
|
|
// Add an event listener to the parseTokenButton
|
|
const parseTokenButton = document.getElementById('parseTokenButton');
|
|
parseTokenButton.addEventListener('click', parseAndDisplayToken);
|
|
|
|
// Function to parse the JWT and display the extracted fields
|
|
function parseAndDisplayToken() {
|
|
const tokenInput = document.getElementById('token');
|
|
const jwt = tokenInput.value;
|
|
|
|
try {
|
|
// Parse the JWT payload (second part of the JWT)
|
|
const payloadBase64 = jwt.split('.')[1];
|
|
const decodedPayload = atob(payloadBase64);
|
|
const payload = JSON.parse(decodedPayload);
|
|
|
|
// Extract the desired fields
|
|
const extractedFields = {
|
|
Audience: payload.aud,
|
|
Issuer: payload.iss,
|
|
ExpirationTime: new Date(payload.exp * 1000).toLocaleString(),
|
|
AppDisplayName: payload.app_displayname,
|
|
AppID: payload.appid,
|
|
Name: payload.name,
|
|
UserPrincipalName: payload.upn,
|
|
Scope: payload.scp,
|
|
TenantID: payload.tid
|
|
};
|
|
|
|
// Display the extracted fields
|
|
const jwtFieldsContainer = document.getElementById('jwtFields');
|
|
jwtFieldsContainer.innerHTML = '';
|
|
for (const field in extractedFields) {
|
|
const fieldDetail = `
|
|
${field}: ${extractedFields[field]}
|
|
`;
|
|
jwtFieldsContainer.innerHTML += fieldDetail;
|
|
}
|
|
} catch (error) {
|
|
const jwtFieldsContainer = document.getElementById('jwtFields');
|
|
jwtFieldsContainer.innerHTML = `Error parsing and displaying JWT: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
</script>
|
|
</body>
|
|
</html>
|