Fork me on GitHub

Safelinkify

npm version www.webmanajemen.com LICENSE GitHub language count Github Workflow GitHub forks GitHub stars

Customized safelink url redirector. Transform and Anonymize all hyperlinks to outbound pages. Useful for SEO external links and ADS.

Demo

pagesourcesamples
/page/safelink.htmlsafelink-decode.js
layout
template
compiler
/page/safelink.html?url=aHR0cHM6Ly…

Installation

Bundles

registrylinkcommands
npmhttps://www.npmjs.com/package/safelinkifynpm i safelinkify -D
githubhttps://github.com/dimaslanjaka/safelinknpm i https://github.com/dimaslanjaka/safelink -D
tarballhttps://github.com/dimaslanjaka/safelink/raw/master/release/safelinkify.tgznpm i https://github.com/dimaslanjaka/safelink/raw/master/release/safelinkify.tgz -D

npm

npm install safelinkify -D

yarn

yarn install safelinkify --dev

Development

git clone --single-branch --branch main https://github.com/dimaslanjaka/safelink foldername
cd foldername
yarn install # npm install
commanddescription
yarn startserve generated docs
yarn devwatch and build docs
npm run docsbuild docs
npm run buildbuild dist

Usages

Setup options:

const options = {
  // exclude patterns (dont anonymize these patterns)
  exclude: ['domain.com', /another.domain.com/, /https?:\/\/?(?:([^*]+)\.)?webmanajemen\.com/, /([a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])?[.])*webmanajemen\.com/],
  // url redirector
  redirect: 'https://www.webmanajemen.com/page/safelink.html?url=',
  // debug
  verbose: false,
  // encryption type = 'base64' | 'aes'
  type: 'base64',
  // password aes, default = root
  password: 'unique-password'
}

Browser

script location: node_modules/safelinkify/dist/bundle.min.js.

Call Core Script:

<script src="dist/bundle.min.js"></script>
<!--or using rawgit-->
<script src="https://raw.githack.com/dimaslanjaka/safelink/main/dist/bundle.min.js"></script>
<!--or using statically-->
<script src="https://cdn.statically.io/gh/dimaslanjaka/safelink/main/dist/bundle.min.js"></script>

Execute functions:

<script>
  const sf = new safelink(options);
  // automated safelinkify all hyperlinks in body
  sf.parse(document.querySelector('body')).then((result)=>{
    console.log(result);
    // in page redirector
    sf.resolveQueryUrl(window.location.href);
  });
</script>

NodeJS

Reference Examples:

Import list

const { safelink } = require('safelinkify');
const { default: safelink } = require('safelinkify/dist/safelink');

Usages Example

import safelinkify from 'safelinkify';
// const safelinkify = require('safelinkify')
const sf = new safelinkify.safelink(options);
const processedExternalLinks = sf.parse(`
<a href="www.example.com/page.php?id=xxxx&name=yyyy" ....>external</a>
<a href="http://www.example.com/page.php?id=xxxx&name=yyyy" ....>external</a>
<a href="https://www.example.com/page.php?id=xxxx&name=yyyy" ....>external</a>
<a href="www.example.com/page.php/404" ....></a>
<a href="http://external.domain.com">internal</a>
<a href="http://www.webmanajemen.com">internal</a>
<a href="http://webmanajemen.com">internal</a>
<a href="#http://webmanajemen.com">#internal</a>
<a href="?http://webmanajemen.com">?internal</a>
<a href="">internal</a>
`);
processedExternalLinks.then(console.log);

/*
<a href="www.example.com/page.php?id=xxxx&name=yyyy" ....>external</a>
<a href="https://www.webmanajemen.com/page/safelink.html?url=aHR0cDovL3d3dy5leGFtcGxlLmNvbS9wYWdlLnBocD9pZD14eHh4Jm5hbWU9eXl5eQ==" ....>external</a>
<a href="https://www.webmanajemen.com/page/safelink.html?url=aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vcGFnZS5waHA/aWQ9eHh4eCZuYW1lPXl5eXk=" ....>external</a>
<a href="www.example.com/page.php/404" ....></a>
<a href="http://external.domain.com">internal</a>
<a href="http://www.webmanajemen.com">internal</a>
<a href="http://webmanajemen.com">internal</a>
<a href="#http://webmanajemen.com">#internal</a>
<a href="?http://webmanajemen.com">?internal</a>
<a href="">internal</a>
*/

Using gulp

Reference Examples:

Usages:

import gulp from 'gulp'
import sf from 'safelinkify'
import { toUnix, join } from 'upath'
import through2 from 'through2'

// folder to scan
const destDir = join(__dirname, 'build')
// scan external link to safelink from dest dir
gulp.task('safelink', () => {
  const safelink = new sf.safelink({
    // exclude patterns (dont anonymize these patterns)
    exclude: [
      /https?:\/\/?(?:([^*]+)\.)?webmanajemen\.com/,
      /([a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])?[.])*webmanajemen\.com/
    ],
    // url redirector
    redirect: 'https://www.webmanajemen.com/page/safelink.html?url=',
    // debug
    verbose: false,
    // encryption type = 'base64' | 'aes'
    type: 'base64',
    // password aes, default = root
    password: 'unique-password'
  })
  return gulp
    .src(['**/*.html'], {
      cwd: destDir,
      ignore: [
        // exclude non-website and react production files
        '**/tmp/**',
        '**/node_modules/**',
        '**/monsters/**/*',
        '**/attendants/**/*',
        '**/materials/**/*',
        '**/scenic-spots/**/*',
        '**/static/**/*'
      ]
    })
    .pipe(
      through2.obj(async (file, _enc, next) => {
        // drop null
        if (file.isNull()) return next()
        // do safelinkify
        const content = String(file.contents)
        const parsed = await safelink.parse(content)
        if (parsed) {
          file.contents = Buffer.from(parsed)
          next(null, file)
        } else {
          console.log(
            'cannot parse',
            toUnix(file.path).replace(toUnix(process.cwd()), '')
          )
          next()
        }
      })
    )
    .pipe(gulp.dest(destDir))
})

Safelink Playground

Using QueryResolver only for redirect page
Query URL Resolver Samples
To Encode Or Wrong URL
Decode base64
Decode AES
Decode AES using hash
External Link Samples (Hover)
example google facebook
Internal Link Samples (Hover)
Homepage Search
global parseQuerytypeof window.parseQuery
global resolveQueryUrltypeof window.resolveQueryUrl

Current Page Script

    
<script src="dist/bundle.min.js"></script>
<script>/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference path="../../dist/index.d.ts" />

document.addEventListener('DOMContentLoaded', function () {
  const table = document.querySelector('table#table');
  table.querySelector('#resolveQueryUrl').innerHTML = typeof window.resolveQueryUrl;
  table.querySelector('#parseQuery').innerHTML = typeof window.parseQuery;

  /**
   * Check if variable is ES5 class
   * @param {any} f
   * @returns {boolean}
   */
  function isClass(f) {
    return (
      typeof f === 'function' &&
      (() => {
        try {
          f();
          return false;
        } catch {
          return true;
        }
      })()
    );
  }

  const isSafelinkClass = isClass(window.safelink);
  table.innerHTML += `<tr><td>global safelink</td> <td><code class="language-javascript">isClass(window.safelink)</code></td><td>is ES5 Class: ${isSafelinkClass}</td></tr>`;
  table.innerHTML += `<tr><td>global safelink</td> <td><code class="language-javascript">typeof window.safelink</code></td><td>${typeof window.safelink}</td></tr>`;

  if (isSafelinkClass) {
    const instance = new window.safelink({
      // exclude patterns (dont anonymize these patterns)
      exclude: [/([a-z0-9](?:[a-z0-9-]{1,61}[a-z0-9])?[.])*webmanajemen\.com/],
      // url redirector
      redirect: 'https://www.webmanajemen.com/page/safelink.html?url=',
      // debug
      verbose: false,
      // encryption type = 'base64' | 'aes'
      type: 'base64',
      // password aes, default = root
      password: 'unique-password'
    });
    instance.parse(document.querySelector('div#external'));
    instance.parse(document.querySelector('div#internal'));

    const currentQuery = JSON.stringify(instance.resolveQueryUrl(location.href), null, 2);
    table.innerHTML += `<tr id="current-queries"><td>Redirector Resolver <a href="#query-url" class="btn btn-sm btn-warning">Change</a></td> <td><code>window.safelink.resolveQueryUrl(location.href)</code></td><td><pre><code class="language-json">${currentQuery}</code></pre></td></tr>`;

    const param = new URLSearchParams(window.location.search);
    if (param.has('o') || param.has('url') || location.href.match(/#(o|url)=/)) {
      document.getElementById('current-queries').scrollIntoView();
    }
  }

  Array.from(document.links).forEach((el) => {
    if (!el.innerHTML.length) {
      el.textContent = el.getAttribute('href');
      el.addEventListener('click', (e) => {
        e.preventDefault();
        window.location.href = el.href;
        if (el.href.match(/#(o|url)=/)) location.reload();
      });
    }
  });
});
</script>
    
  

CHANGELOG of safelinkify

1.0.0

  • initial commit

1.0.1

  • fix aes

1.0.2

  • fix object encyrption result

1.0.3

  • add password aes option

1.0.5 - 1.0.6

  • remove useless dependencies
  • detach private script
  • add object redirect url to result query parser

1.0.7

  • fix query string resolver

1.0.8 - 1.0.9

  • fix process on nodejs

1.1.0

  • fix main file js

1.1.1

  • fix process on nodejs read from file

1.1.2

  • fix same link when included as other element (non-hyperlink)

1.1.3

  • Compile to ES5

1.1.4

  • parse now async
  • parse always return string
  • add more docs for easy development
  • add tsconfig.build.json excluding test files
  • [ 2022-10-17 01:49:39 ] 3cafc9d Update README.md
  • [ 2022-10-17 01:55:33 ] 5298e34 Update CHANGELOG.md
  • [ 2022-10-17 01:58:21 ] 2974c3a update docs
  • [ 2022-10-26 09:03:33 ] d50f681 update dependencies

1.1.5

  • [ 2022-11-09 16:30:14 ] b5b6896 add OR
  • [ 2022-11-09 16:31:28 ] ae6fca5 add null validation
  • [ 2022-11-09 16:32:08 ] 6011523 Update safelink.yml
  • [ 2022-11-09 16:33:27 ] 61c0d03 Using npm
  • [ 2022-11-09 16:37:43 ] ecc409f add commits
  • [ 2022-11-09 16:38:18 ] abd46eb update build
  • [ 2022-11-09 16:53:11 ] d63681d Update safelink.yml
  • [ 2022-11-09 16:53:44 ] 5acfae9 Update safelink.yml
  • [ 2022-11-09 16:54:14 ] 96ba98c Update safelink.yml
  • [ 2022-11-09 16:59:58 ] 600ae45 Update safelink.yml
  • [ 2022-11-09 17:06:39 ] 4c865fe update build

1.1.6

1.1.7

1.1.8

1.1.9

1.1.10

1.1.11

1.1.12

1.1.13

  • all commits truncated here

1.2.1