feat(new tool): Outlook Safelink Decoder (#911)

* feat(new tool): Outlook Safelink Decoder

Fix #897

* Use native URL parsing

Co-authored-by: Corentin THOMASSET <corentin.thomasset74@gmail.com>

* Update src/tools/safelink-decoder/index.ts

---------

Co-authored-by: Corentin THOMASSET <corentin.thomasset74@gmail.com>
This commit is contained in:
sharevb 2024-03-11 11:19:32 +01:00 committed by GitHub
parent fe349ad69b
commit d3b32cc14e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 74 additions and 1 deletions

View File

@ -5,7 +5,7 @@ import { tool as basicAuthGenerator } from './basic-auth-generator';
import { tool as asciiTextDrawer } from './ascii-text-drawer';
import { tool as textToUnicode } from './text-to-unicode';
import { tool as safelinkDecoder } from './safelink-decoder';
import { tool as pdfSignatureChecker } from './pdf-signature-checker';
import { tool as numeronymGenerator } from './numeronym-generator';
import { tool as macAddressGenerator } from './mac-address-generator';
@ -127,6 +127,7 @@ export const toolsByCategory: ToolCategory[] = [
userAgentParser,
httpStatusCodes,
jsonDiff,
safelinkDecoder,
],
},
{

View File

@ -0,0 +1,12 @@
import { Mailbox } from '@vicons/tabler';
import { defineTool } from '../tool';
export const tool = defineTool({
name: 'Outlook Safelink decoder',
path: '/safelink-decoder',
description: 'Decode Outlook SafeLink links',
keywords: ['outlook', 'safelink', 'decoder'],
component: () => import('./safelink-decoder.vue'),
icon: Mailbox,
createdAt: new Date('2024-03-11'),
});

View File

@ -0,0 +1,21 @@
import { describe, expect, it } from 'vitest';
import { decodeSafeLinksURL } from './safelink-decoder.service';
describe('safelink-decoder', () => {
describe('decodeSafeLinksURL', () => {
describe('decode outlook safelink urls', () => {
it('should decode basic safelink urls', () => {
expect(decodeSafeLinksURL('https://aus01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.google.com%2Fsearch%3Fq%3Dsafelink%26rlz%3D1&data=05%7C02%7C%7C1ed07253975b46da1d1508dc3443752a%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638442711583216725%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&sdata=%2BQY0HBnnxfI7pzZoxzlhZdDvYu80LwQB0zUUjrffVnk%3D&reserved=0'))
.toBe('https://www.google.com/search?q=safelink&rlz=1');
});
it('should decode encoded safelink urls', () => {
expect(decodeSafeLinksURL('https://aus01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.google.com%2Fsearch%3Fq%3Dsafelink%26rlz%3D1&amp;data=05%7C02%7C%7C1ed07253975b46da1d1508dc3443752a%7C84df9e7fe9f640afb435aaaaaaaaaaaa%7C1%7C0%7C638442711583216725%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C0%7C%7C%7C&amp;sdata=%2BQY0HBnnxfI7pzZoxzlhZdDvYu80LwQB0zUUjrffVnk%3D&amp;reserved=0'))
.toBe('https://www.google.com/search?q=safelink&rlz=1');
});
it('throw on not outlook safelink urls', () => {
expect(() => decodeSafeLinksURL('https://google.com'))
.toThrow('Invalid SafeLinks URL provided');
});
});
});
});

View File

@ -0,0 +1,7 @@
export function decodeSafeLinksURL(safeLinksUrl: string) {
if (!safeLinksUrl.match(/\.safelinks\.protection\.outlook\.com/)) {
throw new Error('Invalid SafeLinks URL provided');
}
return new URL(safeLinksUrl).searchParams.get('url');
}

View File

@ -0,0 +1,32 @@
<script setup lang="ts">
import { decodeSafeLinksURL } from './safelink-decoder.service';
import TextareaCopyable from '@/components/TextareaCopyable.vue';
const inputSafeLinkUrl = ref('');
const outputDecodedUrl = computed(() => {
try {
return decodeSafeLinksURL(inputSafeLinkUrl.value);
}
catch (e: any) {
return e.toString();
}
});
</script>
<template>
<div>
<c-input-text
v-model:value="inputSafeLinkUrl"
raw-text
placeholder="Your input Outlook SafeLink Url..."
autofocus
label="Your input Outlook SafeLink Url:"
/>
<n-divider />
<n-form-item label="Output decoded URL:">
<TextareaCopyable :value="outputDecodedUrl" :word-wrap="true" />
</n-form-item>
</div>
</template>