Skip to content

Instantly share code, notes, and snippets.

@Criomby
Last active April 8, 2023 05:39
Show Gist options
  • Save Criomby/26fa7a4ee2eaefbc1d3212e35b1dce07 to your computer and use it in GitHub Desktop.
Save Criomby/26fa7a4ee2eaefbc1d3212e35b1dce07 to your computer and use it in GitHub Desktop.
openpassword.app
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- fonts -->
<link href="https://fonts.googleapis.com/css?family=Montserrat:100,200,300,700" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Fira+Code" rel="stylesheet">
<!-- favicons
generated using: https://realfavicongenerator.net/ -->
<link rel="apple-touch-icon" sizes="180x180" href="{{ url_for('static', filename='/favicons/apple-touch-icon.png') }}">
<link rel="icon" type="image/png" sizes="32x32" href="{{ url_for('static', filename='/favicons/favicon-32x32.png') }}">
<link rel="icon" type="image/png" sizes="16x16" href="{{ url_for('static', filename='/favicons/favicon-16x16.png') }}">
<link rel="manifest" href="{{ url_for('static', filename='/favicons/site.webmanifest') }}">
<link rel="mask-icon" href="{{ url_for('static', filename='/favicons/safari-pinned-tab.svg') }}" color="#5bbad5">
<meta name="msapplication-TileColor" content="#da532c">
<meta name="theme-color" content="#ffffff">
<!-- CSS -->
<link href="{{ url_for('static', filename='css/styles.css') }}" rel="stylesheet">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.3.1/dist/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.9.1/font/bootstrap-icons.css">
<!-- JS custom script -->
<script type="text/javascript">
var siteVersion = {{ site_version | tojson }};
</script>
<script src="{{ url_for('static', filename='scripts/site.js') }}" defer></script>
<!-- passgen JS -->
<script type="text/javascript" src="{{ url_for('static', filename='scripts/zxcvbn.js') }}" defer></script>
<!-- passgen JS -->
<script src="{{ url_for('static', filename='scripts/openpassword.js') }}" defer></script>
<!-- Underscore.js -->
<script type="text/javascript" type="module" src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.13.4/underscore-umd-min.js"></script>
<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI="
crossorigin="anonymous"></script>
<!-- font awesome -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/js/all.min.js" integrity="sha512-6PM0qYu5KExuNcKt5bURAoT6KCThUmHRewN3zUFNaoI6Di7XJPTMoT6K0nsagZKk2OB4L7E3q1uQKHNHd4stIQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- popper -->
<script src="https://unpkg.com/@popperjs/core@2"></script>
<title>OpenPassword</title>
</head>
<body id="body-passgen">
<center>
<div class="section-container">
<img id="logo" src="{{ url_for('static', filename='images/OpenPassword-logos_transparent.png') }}">
<div class="subtitle">Safe client-side password generator</div>
</div>
<hr class='section_divider'>
<div class="section-container">
<div style="border: 3px dashed ghostwhite; border-radius: 5px; padding: 10px 5px 10px 5px;">
<h2><span class="badge badge-info">Information</span></h2>
The passwords are generated <b>directly on your device</b>.<br class="non-mobile-break">
No data is sent across the internet during this process.<br class="non-mobile-break">
You can even <b>turn off WiFi</b> once the site is fully loaded.
</div>
</div>
<hr class='section_divider'>
<div class="section-container">
<p style="color: white; font-size: 2rem;">Check your passwords:</p>
<div>
<input id="check-password-input" type="text" class="input-field" placeholder="Enter your current password">
<div id="progressbar-container" role="progressbar" class="progressbar" style="margin-top: 20px;">
<div id="progressbar-progress" role="progressbar" class="progressbar inner"></div>
</div>
<p style="margin-top: 15px;">
<b><span id="pass-check-rating-string"></span></b>
</p>
<p id="crack-times" style="margin-top: 15px; display: none;">
<span>Crack times:</span><br>
Online: <b><span id="check-tts-online"></span></b><br>
Offline: <b><span id="check-tts-offline"></span></b>
</p>
</div>
</div>
<hr class='section_divider'>
<div class="section-container">
<p style="color: white; font-size: 1.5rem;">Get a new password:</p>
<!-- Tab links -->
<div class="tab">
<button class="tablinks" onclick="openTab(event, 'traditional')" id="defaultOpen">
<i class="bi bi-1-circle align-btn-cont"></i><br>
<span class="align-btn-cont tab-name" style="white-space: pre;">traditional</span>
</button>
<button class="tablinks" onclick="openTab(event, 'mnemonic')">
<i class="bi bi-2-circle align-btn-cont"></i><br>
<span class="align-btn-cont tab-name" style="white-space: pre;">mnemonic</span>
</button>
<button class="tablinks" onclick="openTab(event, 'hexadecimal')">
<i class="bi bi-3-circle align-btn-cont"></i><br>
<span class="align-btn-cont tab-name" style="white-space: pre;">hexadecimal</span>
</button>
</div>
<!-- Tab content traditional -->
<div id="traditional" class="tabcontent">
<div style="margin-top: 10px;">
<h3>Traditional password</h3>
<p>String of randomized ASCII characters.</p>
<p style="color: grey;">Example:<br><span style="color: dimgrey;">UvDY?V%qf\y7Y96u'[</span></p>
</div>
<div class="glass-box" style="padding: 5px 0px 15px 0px; max-width: 32rem; margin-bottom: 15px;">
<div class="slidecontainer">
<output class="sliderValue" id="sliderValueLength"></output><br>
<input type="range" min="1" max="100" value="12" class="range-slider" id="sliderLength">
</div>
</div>
<div class="glass-box" style="max-width: 32rem; padding: 3px 0px 0px 0px;">
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">All </h2>
</div>
<div class="right">
<label class="switch" for="chkAll">
<input type="checkbox" id="chkAll" />
<div class="slider round"></div>
</label>
</div>
</div>
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">Lower </h2>
</div>
<div class="right">
<label class="switch" for="chkLower">
<input type="checkbox" id="chkLower" />
<div class="slider round"></div>
</label>
</div>
</div>
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">Upper </h2>
</div>
<div class="right">
<label class="switch" for="chkUpper">
<input type="checkbox" id="chkUpper" />
<div class="slider round"></div>
</label>
</div>
</div>
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">Digits </h2>
</div>
<div class="right">
<label class="switch" for="chkDigits">
<input type="checkbox" id="chkDigits" />
<div class="slider round"></div>
</label>
</div>
</div>
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">Punct. </h2>
</div>
<div class="right">
<label class="switch" for="chkPunct">
<input type="checkbox" id="chkPunct" />
<div class="slider round"></div>
</label>
</div>
</div>
</div>
<button id="btn-rand" class="btn-rand" role="button"><i class="fa-solid fa-wand-magic-sparkles"></i> randomize</button>
<p>Random password between 4 & 32 characters.</p>
</div>
<!-- Tab content mnem -->
<div id="mnemonic" class="tabcontent">
<div style="margin-top: 10px;">
<h3>Mnemonic passphrase</h3>
<p>Easy to remember, more secure than most traditional passwords.</p>
<p style="color: grey;">Example:<br><span style="color: dimgrey;">glove metal group spice craft</span></p>
<p>
<a href="https://usa.kaspersky.com/blog/remember-strong-passwords/4703/" class="hover-underline-animation">Why is that?</a><br>
<span style="color: grey;">
<span class="badge badge-warning">External Link</span><br>
(usa.kaspersky.com)
</span>
</p>
</div>
<div class="glass-box" style="padding: 5px 0px 15px 0px; max-width: 32rem; margin-bottom: 15px;">
<div class="slidecontainer">
<output class="sliderValue" id="sliderValueWords"></output><br>
<input type="range" min="1" max="32" value="3" class="range-slider" id="sliderWords">
</div>
</div>
<div class="glass-box" style="max-width: 32rem; padding: 3px 0px 0px 0px;">
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">whitespace </h2>
</div>
<div class="right">
<label class="switch" for="chkWhite">
<input type="checkbox" id="chkWhite" />
<div class="slider round"></div>
</label>
</div>
</div>
</div>
</div>
<!-- Tab content hex -->
<div id="hexadecimal" class="tabcontent">
<div style="margin-top: 10px;">
<h3>Hexadecimal string</h3>
<p>
<a href="https://en.wikipedia.org/wiki/Hexadecimal" class="hover-underline-animation">What is hexadecimal?</a><br>
<span style="color: grey;">
<span class="badge badge-warning">External Link</span><br>
(wikipedia.com)
</span>
</p>
<p style="color: grey;">Example:<br><span style="color: dimgrey;">0x32ef9eb63b4f585e</span></p>
</div>
<div class="glass-box" style="padding: 5px 0px 15px 0px; max-width: 32rem; margin-bottom: 15px;">
<div class="slidecontainer">
<output class="sliderValue" id="sliderValueLenHex"></output><br>
<input type="range" min="1" max="64" value="16" class="range-slider" id="sliderLenHex">
</div>
</div>
<div class="glass-box" style="max-width: 32rem; padding: 3px 0px 0px 0px;">
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">Chars</h2>
</div>
<div class="mid">
<label class="switch" for="chkLenType">
<input type="checkbox" id="chkLenType" />
<div class="slider round"></div>
</label>
</div>
<div class="right">
<h2 style="white-space: pre;">Bytes</h2>
</div>
</div>
<div class="section-row">
<div class="left">
<h2 style="white-space: pre;">identifier (0x) </h2>
</div>
<div class="right">
<label class="switch" for="chkIdent">
<input type="checkbox" id="chkIdent" />
<div class="slider round"></div>
</label>
</div>
</div>
</div>
</div>
<button id="btnReset" class="button-reset" role="button"><i class="fa-solid fa-delete-left"></i> reset</button>
<hr class='section_divider'>
<button id="btn-passgen" class="button-20" role="button"><i class="fa-solid fa-gears"></i> Generate</button>
<div id="tooltip" role="tooltip">
<span id="popper-text">Password copied!</span>
<div id="arrow" data-popper-arrow></div>
</div>
<button id="btn-copy" class="button-copy" role="button"><i class="fa-regular fa-copy"></i> Copy</button>
<div>
<input id="outField" type="text" class="input-field" placeholder="Your pasword will show here" readonly>
</div>
<div style="margin-bottom: 30px;"></div>
</div>
<hr class='section_divider'>
<div class="section-container">
<h4 class='section-header'>How does it work?</h4>
<p class="section-content" style="text-align: justify;">
This is a client-side password generator.<br>
That means that everything done on this webpage with regard to the password generation is done on your local device.
There is no data sent across the internet which makes it more secure than most other webistes which generate the password
on the server and send it back to you which poses a security thread as the data may be captured or monitored by other parties, especially the server owner or service provider.<br>
Also, this web service (and the whole website) does not collect any kind of information from you.<br><br>
The application is written in TypeScript.<br>
The source code of the password generator is open-source so you can have a look at the code to see the actual stuff that is going on when you create a password.<br>
The password checker functionality is implemented using the great "zxcvbn.js" mdoule developed by Dropbox to check the password.
</p>
<br>
<span>Source code:</span><br>
<button id="btn-github" class="button-21" role="button">
<i class="fa-brands fa-github align-btn-cont" style="font-size: 2rem;"></i>
<span class="align-btn-cont" style="white-space: pre; font-size: 1.5rem;" onclick="openInNewTab('https://github.com/Criomby/openPassword')">GitHub</span>
</button>
<span><h2><b>and</b></h2></span>
<div style="margin-top: 20px;">
<a href="https://www.buymeacoffee.com/philippebraum" target="_blank">
<img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" >
</a>
</div>
</div>
<hr class='section_divider'>
<div id="footer" class="footer white">
<!-- content added with JS -->
</div>
</center>
</body>
</html>
/*
openpassword.ts
OpenPassword (openpassword.app)
Copyright (C) 2023 Philippe Braum (@Criomby)
TS script to generate various types of passwords
Available under the Apache 2.0 license
*/
// password generator class
class PassGen {
passType: number; // one of [1, 2, 3] (type 1: alphanumeric password, type 2: mnemonic passphrase, type 3: hexadecimal string)
// traditional password
readonly asciiLower: string = "abcdefghijklmnopqrstuvwqyz";
readonly asciiUpper: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
readonly asciiPunct: string = String.raw`!"#$%&'()*+,-./:;<=>?@[\]^_\`{}~`; // excluded '¦' to make the passwords manually writable with any standard keyboard
readonly asciiDigits: string = "0123456789";
lengthChars: number;
lower: boolean;
upper: boolean;
digits: boolean;
punct: boolean;
_all: boolean;
// mnemonic
lengthWords: number;
// BIP0039 wordlist for mnemonic passphrases
readonly BIP39: Array<string> = ['abandon', 'ability', 'able', 'about', 'above', 'absent', 'absorb', 'abstract', 'absurd', 'abuse', 'access', 'accident', 'account', 'accuse', 'achieve', 'acid', 'acoustic', 'acquire', 'across', 'act', 'action', 'actor', 'actress', 'actual', 'adapt', 'add', 'addict', 'address', 'adjust', 'admit', 'adult', 'advance', 'advice', 'aerobic', 'affair', 'afford', 'afraid', 'again', 'age', 'agent', 'agree', 'ahead', 'aim', 'air', 'airport', 'aisle', 'alarm', 'album', 'alcohol', 'alert', 'alien', 'all', 'alley', 'allow', 'almost', 'alone', 'alpha', 'already', 'also', 'alter', 'always', 'amateur', 'amazing', 'among', 'amount', 'amused', 'analyst', 'anchor', 'ancient', 'anger', 'angle', 'angry', 'animal', 'ankle', 'announce', 'annual', 'another', 'answer', 'antenna', 'antique', 'anxiety', 'any', 'apart', 'apology', 'appear', 'apple', 'approve', 'april', 'arch', 'arctic', 'area', 'arena', 'argue', 'arm', 'armed', 'armor', 'army', 'around', 'arrange', 'arrest', 'arrive', 'arrow', 'art', 'artefact', 'artist', 'artwork', 'ask', 'aspect', 'assault', 'asset', 'assist', 'assume', 'asthma', 'athlete', 'atom', 'attack', 'attend', 'attitude', 'attract', 'auction', 'audit', 'august', 'aunt', 'author', 'auto', 'autumn', 'average', 'avocado', 'avoid', 'awake', 'aware', 'away', 'awesome', 'awful', 'awkward', 'axis', 'baby', 'bachelor', 'bacon', 'badge', 'bag', 'balance', 'balcony', 'ball', 'bamboo', 'banana', 'banner', 'bar', 'barely', 'bargain', 'barrel', 'base', 'basic', 'basket', 'battle', 'beach', 'bean', 'beauty', 'because', 'become', 'beef', 'before', 'begin', 'behave', 'behind', 'believe', 'below', 'belt', 'bench', 'benefit', 'best', 'betray', 'better', 'between', 'beyond', 'bicycle', 'bid', 'bike', 'bind', 'biology', 'bird', 'birth', 'bitter', 'black', 'blade', 'blame', 'blanket', 'blast', 'bleak', 'bless', 'blind', 'blood', 'blossom', 'blouse', 'blue', 'blur', 'blush', 'board', 'boat', 'body', 'boil', 'bomb', 'bone', 'bonus', 'book', 'boost', 'border', 'boring', 'borrow', 'boss', 'bottom', 'bounce', 'box', 'boy', 'bracket', 'brain', 'brand', 'brass', 'brave', 'bread', 'breeze', 'brick', 'bridge', 'brief', 'bright', 'bring', 'brisk', 'broccoli', 'broken', 'bronze', 'broom', 'brother', 'brown', 'brush', 'bubble', 'buddy', 'budget', 'buffalo', 'build', 'bulb', 'bulk', 'bullet', 'bundle', 'bunker', 'burden', 'burger', 'burst', 'bus', 'business', 'busy', 'butter', 'buyer', 'buzz', 'cabbage', 'cabin', 'cable', 'cactus', 'cage', 'cake', 'call', 'calm', 'camera', 'camp', 'can', 'canal', 'cancel', 'candy', 'cannon', 'canoe', 'canvas', 'canyon', 'capable', 'capital', 'captain', 'car', 'carbon', 'card', 'cargo', 'carpet', 'carry', 'cart', 'case', 'cash', 'casino', 'castle', 'casual', 'cat', 'catalog', 'catch', 'category', 'cattle', 'caught', 'cause', 'caution', 'cave', 'ceiling', 'celery', 'cement', 'census', 'century', 'cereal', 'certain', 'chair', 'chalk', 'champion', 'change', 'chaos', 'chapter', 'charge', 'chase', 'chat', 'cheap', 'check', 'cheese', 'chef', 'cherry', 'chest', 'chicken', 'chief', 'child', 'chimney', 'choice', 'choose', 'chronic', 'chuckle', 'chunk', 'churn', 'cigar', 'cinnamon', 'circle', 'citizen', 'city', 'civil', 'claim', 'clap', 'clarify', 'claw', 'clay', 'clean', 'clerk', 'clever', 'click', 'client', 'cliff', 'climb', 'clinic', 'clip', 'clock', 'clog', 'close', 'cloth', 'cloud', 'clown', 'club', 'clump', 'cluster', 'clutch', 'coach', 'coast', 'coconut', 'code', 'coffee', 'coil', 'coin', 'collect', 'color', 'column', 'combine', 'come', 'comfort', 'comic', 'common', 'company', 'concert', 'conduct', 'confirm', 'congress', 'connect', 'consider', 'control', 'convince', 'cook', 'cool', 'copper', 'copy', 'coral', 'core', 'corn', 'correct', 'cost', 'cotton', 'couch', 'country', 'couple', 'course', 'cousin', 'cover', 'coyote', 'crack', 'cradle', 'craft', 'cram', 'crane', 'crash', 'crater', 'crawl', 'crazy', 'cream', 'credit', 'creek', 'crew', 'cricket', 'crime', 'crisp', 'critic', 'crop', 'cross', 'crouch', 'crowd', 'crucial', 'cruel', 'cruise', 'crumble', 'crunch', 'crush', 'cry', 'crystal', 'cube', 'culture', 'cup', 'cupboard', 'curious', 'current', 'curtain', 'curve', 'cushion', 'custom', 'cute', 'cycle', 'dad', 'damage', 'damp', 'dance', 'danger', 'daring', 'dash', 'daughter', 'dawn', 'day', 'deal', 'debate', 'debris', 'decade', 'december', 'decide', 'decline', 'decorate', 'decrease', 'deer', 'defense', 'define', 'defy', 'degree', 'delay', 'deliver', 'demand', 'demise', 'denial', 'dentist', 'deny', 'depart', 'depend', 'deposit', 'depth', 'deputy', 'derive', 'describe', 'desert', 'design', 'desk', 'despair', 'destroy', 'detail', 'detect', 'develop', 'device', 'devote', 'diagram', 'dial', 'diamond', 'diary', 'dice', 'diesel', 'diet', 'differ', 'digital', 'dignity', 'dilemma', 'dinner', 'dinosaur', 'direct', 'dirt', 'disagree', 'discover', 'disease', 'dish', 'dismiss', 'disorder', 'display', 'distance', 'divert', 'divide', 'divorce', 'dizzy', 'doctor', 'document', 'dog', 'doll', 'dolphin', 'domain', 'donate', 'donkey', 'donor', 'door', 'dose', 'double', 'dove', 'draft', 'dragon', 'drama', 'drastic', 'draw', 'dream', 'dress', 'drift', 'drill', 'drink', 'drip', 'drive', 'drop', 'drum', 'dry', 'duck', 'dumb', 'dune', 'during', 'dust', 'dutch', 'duty', 'dwarf', 'dynamic', 'eager', 'eagle', 'early', 'earn', 'earth', 'easily', 'east', 'easy', 'echo', 'ecology', 'economy', 'edge', 'edit', 'educate', 'effort', 'egg', 'eight', 'either', 'elbow', 'elder', 'electric', 'elegant', 'element', 'elephant', 'elevator', 'elite', 'else', 'embark', 'embody', 'embrace', 'emerge', 'emotion', 'employ', 'empower', 'empty', 'enable', 'enact', 'end', 'endless', 'endorse', 'enemy', 'energy', 'enforce', 'engage', 'engine', 'enhance', 'enjoy', 'enlist', 'enough', 'enrich', 'enroll', 'ensure', 'enter', 'entire', 'entry', 'envelope', 'episode', 'equal', 'equip', 'era', 'erase', 'erode', 'erosion', 'error', 'erupt', 'escape', 'essay', 'essence', 'estate', 'eternal', 'ethics', 'evidence', 'evil', 'evoke', 'evolve', 'exact', 'example', 'excess', 'exchange', 'excite', 'exclude', 'excuse', 'execute', 'exercise', 'exhaust', 'exhibit', 'exile', 'exist', 'exit', 'exotic', 'expand', 'expect', 'expire', 'explain', 'expose', 'express', 'extend', 'extra', 'eye', 'eyebrow', 'fabric', 'face', 'faculty', 'fade', 'faint', 'faith', 'fall', 'false', 'fame', 'family', 'famous', 'fan', 'fancy', 'fantasy', 'farm', 'fashion', 'fat', 'fatal', 'father', 'fatigue', 'fault', 'favorite', 'feature', 'february', 'federal', 'fee', 'feed', 'feel', 'female', 'fence', 'festival', 'fetch', 'fever', 'few', 'fiber', 'fiction', 'field', 'figure', 'file', 'film', 'filter', 'final', 'find', 'fine', 'finger', 'finish', 'fire', 'firm', 'first', 'fiscal', 'fish', 'fit', 'fitness', 'fix', 'flag', 'flame', 'flash', 'flat', 'flavor', 'flee', 'flight', 'flip', 'float', 'flock', 'floor', 'flower', 'fluid', 'flush', 'fly', 'foam', 'focus', 'fog', 'foil', 'fold', 'follow', 'food', 'foot', 'force', 'forest', 'forget', 'fork', 'fortune', 'forum', 'forward', 'fossil', 'foster', 'found', 'fox', 'fragile', 'frame', 'frequent', 'fresh', 'friend', 'fringe', 'frog', 'front', 'frost', 'frown', 'frozen', 'fruit', 'fuel', 'fun', 'funny', 'furnace', 'fury', 'future', 'gadget', 'gain', 'galaxy', 'gallery', 'game', 'gap', 'garage', 'garbage', 'garden', 'garlic', 'garment', 'gas', 'gasp', 'gate', 'gather', 'gauge', 'gaze', 'general', 'genius', 'genre', 'gentle', 'genuine', 'gesture', 'ghost', 'giant', 'gift', 'giggle', 'ginger', 'giraffe', 'girl', 'give', 'glad', 'glance', 'glare', 'glass', 'glide', 'glimpse', 'globe', 'gloom', 'glory', 'glove', 'glow', 'glue', 'goat', 'goddess', 'gold', 'good', 'goose', 'gorilla', 'gospel', 'gossip', 'govern', 'gown', 'grab', 'grace', 'grain', 'grant', 'grape', 'grass', 'gravity', 'great', 'green', 'grid', 'grief', 'grit', 'grocery', 'group', 'grow', 'grunt', 'guard', 'guess', 'guide', 'guilt', 'guitar', 'gun', 'gym', 'habit', 'hair', 'half', 'hammer', 'hamster', 'hand', 'happy', 'harbor', 'hard', 'harsh', 'harvest', 'hat', 'have', 'hawk', 'hazard', 'head', 'health', 'heart', 'heavy', 'hedgehog', 'height', 'hello', 'helmet', 'help', 'hen', 'hero', 'hidden', 'high', 'hill', 'hint', 'hip', 'hire', 'history', 'hobby', 'hockey', 'hold', 'hole', 'holiday', 'hollow', 'home', 'honey', 'hood', 'hope', 'horn', 'horror', 'horse', 'hospital', 'host', 'hotel', 'hour', 'hover', 'hub', 'huge', 'human', 'humble', 'humor', 'hundred', 'hungry', 'hunt', 'hurdle', 'hurry', 'hurt', 'husband', 'hybrid', 'ice', 'icon', 'idea', 'identify', 'idle', 'ignore', 'ill', 'illegal', 'illness', 'image', 'imitate', 'immense', 'immune', 'impact', 'impose', 'improve', 'impulse', 'inch', 'include', 'income', 'increase', 'index', 'indicate', 'indoor', 'industry', 'infant', 'inflict', 'inform', 'inhale', 'inherit', 'initial', 'inject', 'injury', 'inmate', 'inner', 'innocent', 'input', 'inquiry', 'insane', 'insect', 'inside', 'inspire', 'install', 'intact', 'interest', 'into', 'invest', 'invite', 'involve', 'iron', 'island', 'isolate', 'issue', 'item', 'ivory', 'jacket', 'jaguar', 'jar', 'jazz', 'jealous', 'jeans', 'jelly', 'jewel', 'job', 'join', 'joke', 'journey', 'joy', 'judge', 'juice', 'jump', 'jungle', 'junior', 'junk', 'just', 'kangaroo', 'keen', 'keep', 'ketchup', 'key', 'kick', 'kid', 'kidney', 'kind', 'kingdom', 'kiss', 'kit', 'kitchen', 'kite', 'kitten', 'kiwi', 'knee', 'knife', 'knock', 'know', 'lab', 'label', 'labor', 'ladder', 'lady', 'lake', 'lamp', 'language', 'laptop', 'large', 'later', 'latin', 'laugh', 'laundry', 'lava', 'law', 'lawn', 'lawsuit', 'layer', 'lazy', 'leader', 'leaf', 'learn', 'leave', 'lecture', 'left', 'leg', 'legal', 'legend', 'leisure', 'lemon', 'lend', 'length', 'lens', 'leopard', 'lesson', 'letter', 'level', 'liar', 'liberty', 'library', 'license', 'life', 'lift', 'light', 'like', 'limb', 'limit', 'link', 'lion', 'liquid', 'list', 'little', 'live', 'lizard', 'load', 'loan', 'lobster', 'local', 'lock', 'logic', 'lonely', 'long', 'loop', 'lottery', 'loud', 'lounge', 'love', 'loyal', 'lucky', 'luggage', 'lumber', 'lunar', 'lunch', 'luxury', 'lyrics', 'machine', 'mad', 'magic', 'magnet', 'maid', 'mail', 'main', 'major', 'make', 'mammal', 'man', 'manage', 'mandate', 'mango', 'mansion', 'manual', 'maple', 'marble', 'march', 'margin', 'marine', 'market', 'marriage', 'mask', 'mass', 'master', 'match', 'material', 'math', 'matrix', 'matter', 'maximum', 'maze', 'meadow', 'mean', 'measure', 'meat', 'mechanic', 'medal', 'media', 'melody', 'melt', 'member', 'memory', 'mention', 'menu', 'mercy', 'merge', 'merit', 'merry', 'mesh', 'message', 'metal', 'method', 'middle', 'midnight', 'milk', 'million', 'mimic', 'mind', 'minimum', 'minor', 'minute', 'miracle', 'mirror', 'misery', 'miss', 'mistake', 'mix', 'mixed', 'mixture', 'mobile', 'model', 'modify', 'mom', 'moment', 'monitor', 'monkey', 'monster', 'month', 'moon', 'moral', 'more', 'morning', 'mosquito', 'mother', 'motion', 'motor', 'mountain', 'mouse', 'move', 'movie', 'much', 'muffin', 'mule', 'multiply', 'muscle', 'museum', 'mushroom', 'music', 'must', 'mutual', 'myself', 'mystery', 'myth', 'naive', 'name', 'napkin', 'narrow', 'nasty', 'nation', 'nature', 'near', 'neck', 'need', 'negative', 'neglect', 'neither', 'nephew', 'nerve', 'nest', 'net', 'network', 'neutral', 'never', 'news', 'next', 'nice', 'night', 'noble', 'noise', 'nominee', 'noodle', 'normal', 'north', 'nose', 'notable', 'note', 'nothing', 'notice', 'novel', 'now', 'nuclear', 'number', 'nurse', 'nut', 'oak', 'obey', 'object', 'oblige', 'obscure', 'observe', 'obtain', 'obvious', 'occur', 'ocean', 'october', 'odor', 'off', 'offer', 'office', 'often', 'oil', 'okay', 'old', 'olive', 'olympic', 'omit', 'once', 'one', 'onion', 'online', 'only', 'open', 'opera', 'opinion', 'oppose', 'option', 'orange', 'orbit', 'orchard', 'order', 'ordinary', 'organ', 'orient', 'original', 'orphan', 'ostrich', 'other', 'outdoor', 'outer', 'output', 'outside', 'oval', 'oven', 'over', 'own', 'owner', 'oxygen', 'oyster', 'ozone', 'pact', 'paddle', 'page', 'pair', 'palace', 'palm', 'panda', 'panel', 'panic', 'panther', 'paper', 'parade', 'parent', 'park', 'parrot', 'party', 'pass', 'patch', 'path', 'patient', 'patrol', 'pattern', 'pause', 'pave', 'payment', 'peace', 'peanut', 'pear', 'peasant', 'pelican', 'pen', 'penalty', 'pencil', 'people', 'pepper', 'perfect', 'permit', 'person', 'pet', 'phone', 'photo', 'phrase', 'physical', 'piano', 'picnic', 'picture', 'piece', 'pig', 'pigeon', 'pill', 'pilot', 'pink', 'pioneer', 'pipe', 'pistol', 'pitch', 'pizza', 'place', 'planet', 'plastic', 'plate', 'play', 'please', 'pledge', 'pluck', 'plug', 'plunge', 'poem', 'poet', 'point', 'polar', 'pole', 'police', 'pond', 'pony', 'pool', 'popular', 'portion', 'position', 'possible', 'post', 'potato', 'pottery', 'poverty', 'powder', 'power', 'practice', 'praise', 'predict', 'prefer', 'prepare', 'present', 'pretty', 'prevent', 'price', 'pride', 'primary', 'print', 'priority', 'prison', 'private', 'prize', 'problem', 'process', 'produce', 'profit', 'program', 'project', 'promote', 'proof', 'property', 'prosper', 'protect', 'proud', 'provide', 'public', 'pudding', 'pull', 'pulp', 'pulse', 'pumpkin', 'punch', 'pupil', 'puppy', 'purchase', 'purity', 'purpose', 'purse', 'push', 'put', 'puzzle', 'pyramid', 'quality', 'quantum', 'quarter', 'question', 'quick', 'quit', 'quiz', 'quote', 'rabbit', 'raccoon', 'race', 'rack', 'radar', 'radio', 'rail', 'rain', 'raise', 'rally', 'ramp', 'ranch', 'random', 'range', 'rapid', 'rare', 'rate', 'rather', 'raven', 'raw', 'razor', 'ready', 'real', 'reason', 'rebel', 'rebuild', 'recall', 'receive', 'recipe', 'record', 'recycle', 'reduce', 'reflect', 'reform', 'refuse', 'region', 'regret', 'regular', 'reject', 'relax', 'release', 'relief', 'rely', 'remain', 'remember', 'remind', 'remove', 'render', 'renew', 'rent', 'reopen', 'repair', 'repeat', 'replace', 'report', 'require', 'rescue', 'resemble', 'resist', 'resource', 'response', 'result', 'retire', 'retreat', 'return', 'reunion', 'reveal', 'review', 'reward', 'rhythm', 'rib', 'ribbon', 'rice', 'rich', 'ride', 'ridge', 'rifle', 'right', 'rigid', 'ring', 'riot', 'ripple', 'risk', 'ritual', 'rival', 'river', 'road', 'roast', 'robot', 'robust', 'rocket', 'romance', 'roof', 'rookie', 'room', 'rose', 'rotate', 'rough', 'round', 'route', 'royal', 'rubber', 'rude', 'rug', 'rule', 'run', 'runway', 'rural', 'sad', 'saddle', 'sadness', 'safe', 'sail', 'salad', 'salmon', 'salon', 'salt', 'salute', 'same', 'sample', 'sand', 'satisfy', 'satoshi', 'sauce', 'sausage', 'save', 'say', 'scale', 'scan', 'scare', 'scatter', 'scene', 'scheme', 'school', 'science', 'scissors', 'scorpion', 'scout', 'scrap', 'screen', 'script', 'scrub', 'sea', 'search', 'season', 'seat', 'second', 'secret', 'section', 'security', 'seed', 'seek', 'segment', 'select', 'sell', 'seminar', 'senior', 'sense', 'sentence', 'series', 'service', 'session', 'settle', 'setup', 'seven', 'shadow', 'shaft', 'shallow', 'share', 'shed', 'shell', 'sheriff', 'shield', 'shift', 'shine', 'ship', 'shiver', 'shock', 'shoe', 'shoot', 'shop', 'short', 'shoulder', 'shove', 'shrimp', 'shrug', 'shuffle', 'shy', 'sibling', 'sick', 'side', 'siege', 'sight', 'sign', 'silent', 'silk', 'silly', 'silver', 'similar', 'simple', 'since', 'sing', 'siren', 'sister', 'situate', 'six', 'size', 'skate', 'sketch', 'ski', 'skill', 'skin', 'skirt', 'skull', 'slab', 'slam', 'sleep', 'slender', 'slice', 'slide', 'slight', 'slim', 'slogan', 'slot', 'slow', 'slush', 'small', 'smart', 'smile', 'smoke', 'smooth', 'snack', 'snake', 'snap', 'sniff', 'snow', 'soap', 'soccer', 'social', 'sock', 'soda', 'soft', 'solar', 'soldier', 'solid', 'solution', 'solve', 'someone', 'song', 'soon', 'sorry', 'sort', 'soul', 'sound', 'soup', 'source', 'south', 'space', 'spare', 'spatial', 'spawn', 'speak', 'special', 'speed', 'spell', 'spend', 'sphere', 'spice', 'spider', 'spike', 'spin', 'spirit', 'split', 'spoil', 'sponsor', 'spoon', 'sport', 'spot', 'spray', 'spread', 'spring', 'spy', 'square', 'squeeze', 'squirrel', 'stable', 'stadium', 'staff', 'stage', 'stairs', 'stamp', 'stand', 'start', 'state', 'stay', 'steak', 'steel', 'stem', 'step', 'stereo', 'stick', 'still', 'sting', 'stock', 'stomach', 'stone', 'stool', 'story', 'stove', 'strategy', 'street', 'strike', 'strong', 'struggle', 'student', 'stuff', 'stumble', 'style', 'subject', 'submit', 'subway', 'success', 'such', 'sudden', 'suffer', 'sugar', 'suggest', 'suit', 'summer', 'sun', 'sunny', 'sunset', 'super', 'supply', 'supreme', 'sure', 'surface', 'surge', 'surprise', 'surround', 'survey', 'suspect', 'sustain', 'swallow', 'swamp', 'swap', 'swarm', 'swear', 'sweet', 'swift', 'swim', 'swing', 'switch', 'sword', 'symbol', 'symptom', 'syrup', 'system', 'table', 'tackle', 'tag', 'tail', 'talent', 'talk', 'tank', 'tape', 'target', 'task', 'taste', 'tattoo', 'taxi', 'teach', 'team', 'tell', 'ten', 'tenant', 'tennis', 'tent', 'term', 'test', 'text', 'thank', 'that', 'theme', 'then', 'theory', 'there', 'they', 'thing', 'this', 'thought', 'three', 'thrive', 'throw', 'thumb', 'thunder', 'ticket', 'tide', 'tiger', 'tilt', 'timber', 'time', 'tiny', 'tip', 'tired', 'tissue', 'title', 'toast', 'tobacco', 'today', 'toddler', 'toe', 'together', 'toilet', 'token', 'tomato', 'tomorrow', 'tone', 'tongue', 'tonight', 'tool', 'tooth', 'top', 'topic', 'topple', 'torch', 'tornado', 'tortoise', 'toss', 'total', 'tourist', 'toward', 'tower', 'town', 'toy', 'track', 'trade', 'traffic', 'tragic', 'train', 'transfer', 'trap', 'trash', 'travel', 'tray', 'treat', 'tree', 'trend', 'trial', 'tribe', 'trick', 'trigger', 'trim', 'trip', 'trophy', 'trouble', 'truck', 'true', 'truly', 'trumpet', 'trust', 'truth', 'try', 'tube', 'tuition', 'tumble', 'tuna', 'tunnel', 'turkey', 'turn', 'turtle', 'twelve', 'twenty', 'twice', 'twin', 'twist', 'two', 'type', 'typical', 'ugly', 'umbrella', 'unable', 'unaware', 'uncle', 'uncover', 'under', 'undo', 'unfair', 'unfold', 'unhappy', 'uniform', 'unique', 'unit', 'universe', 'unknown', 'unlock', 'until', 'unusual', 'unveil', 'update', 'upgrade', 'uphold', 'upon', 'upper', 'upset', 'urban', 'urge', 'usage', 'use', 'used', 'useful', 'useless', 'usual', 'utility', 'vacant', 'vacuum', 'vague', 'valid', 'valley', 'valve', 'van', 'vanish', 'vapor', 'various', 'vast', 'vault', 'vehicle', 'velvet', 'vendor', 'venture', 'venue', 'verb', 'verify', 'version', 'very', 'vessel', 'veteran', 'viable', 'vibrant', 'vicious', 'victory', 'video', 'view', 'village', 'vintage', 'violin', 'virtual', 'virus', 'visa', 'visit', 'visual', 'vital', 'vivid', 'vocal', 'voice', 'void', 'volcano', 'volume', 'vote', 'voyage', 'wage', 'wagon', 'wait', 'walk', 'wall', 'walnut', 'want', 'warfare', 'warm', 'warrior', 'wash', 'wasp', 'waste', 'water', 'wave', 'way', 'wealth', 'weapon', 'wear', 'weasel', 'weather', 'web', 'wedding', 'weekend', 'weird', 'welcome', 'west', 'wet', 'whale', 'what', 'wheat', 'wheel', 'when', 'where', 'whip', 'whisper', 'wide', 'width', 'wife', 'wild', 'will', 'win', 'window', 'wine', 'wing', 'wink', 'winner', 'winter', 'wire', 'wisdom', 'wise', 'wish', 'witness', 'wolf', 'woman', 'wonder', 'wood', 'wool', 'word', 'work', 'world', 'worry', 'worth', 'wrap', 'wreck', 'wrestle', 'wrist', 'write', 'wrong', 'yard', 'year', 'yellow', 'you', 'young', 'youth', 'zebra', 'zero', 'zone', 'zoo'];
whitespace: boolean;
// hex
readonly hexChars: Array<string> = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'];
hexLen: number; // length of hex string in ["chars", "bytes"]
hexLenType: string; // one of ["chars", "bytes"], defaults to "chars"
hexIdent: boolean; // false: no prefix, true: "0x" prefix, defaults to 1
// TODO #12: Refactor class
constructor() {
}
/*
// getter
get password() {
return this.genPass();
}
*/
// generate password
genPass() {
this.updateValues();
let password: string;
if (this.passType == 1) {
password = this.genAlphanum();
}
else if (this.passType == 2) {
password = this.genMnemonic();
}
else if (this.passType == 3) {
password = this.genHex();
}
else {
password = "ERROR! Please contact site admin.";
}
return password;
}
protected genAlphanum(): string {
let sequence: string = ""; // string
let seqArr: Array<string> = []; // sequence array
let passArr: Array<string> = []; // password as array of chars
let password: string = ""; // final string password
// check options
// error if all false == no options selected
if (this._all == false && this.lower == false && this.upper == false && this.digits == false && this.punct == false) {
// return and send error to output field
return "";
}
if (this._all == true) {
sequence = sequence.concat(this.asciiLower, this.asciiUpper, this.asciiDigits, this.asciiPunct);
}
else {
if (this.lower == true) {
sequence = sequence.concat(this.asciiLower);
}
if (this.upper == true) {
sequence = sequence.concat(this.asciiUpper);
}
if (this.digits == true) {
sequence = sequence.concat(this.asciiDigits);
}
if (this.punct == true) {
sequence = sequence.concat(this.asciiPunct);
}
}
// convert sequence string to array
seqArr = sequence.split("");
// shuffle sequence
// @ts-ignore: Cannot find name '_'
seqArr = _.shuffle(seqArr);
// create password
for (let i = 0; i < this.lengthChars; i++) {
// @ts-ignore: Cannot find name '_'
passArr[i] = _.sample(seqArr);
}
// shuffle password
// @ts-ignore: Cannot find name '_'
passArr = _.shuffle(passArr);
// convert to string
password = passArr.join("");
return password;
}
protected genMnemonic(): string {
// TODO refactor method #20
//let sequence = _.shuffle(this.BIP39);
//let passArr = []; // password as array of words
let password: string; // final string password
let words: Array<string> = [];
for (let i = 0; i < this.lengthWords; i++) {
// @ts-ignore: Cannot find name '_'
words[i] = _.sample(this.BIP39);
}
// @ts-ignore: Cannot find name '_'
words = _.shuffle(words);
if (this.whitespace == true) {
password = words.join(" ");
}
else {
password = words.join("");
}
return password
}
protected genHex(): string {
let hexstring: string = "";
let stringSize = this.hexLen;
if (this.hexLenType == "bytes") {
// one hex symbol (0-9, a-f) is 4 bits so two chars are one byte (8 bits), has to be twice the amount of chars therfore if length is given in bytes
stringSize *= 2;
}
for (let i = 0; i < stringSize; i++) {
// @ts-ignore: Cannot find name '_'
hexstring += _.sample(this.hexChars);
}
if (this.hexIdent == true) {
hexstring = "0x" + hexstring;
}
return hexstring;
}
// get checkbox values
protected updateValues(): void {
// check which tab is active
if (btnTraditional.classList.contains("active")) {
this.passType = 1;
}
else if (btnMnemonic.classList.contains("active")) {
this.passType = 2;
}
else if (btnHexadecimal.classList.contains("active")) {
this.passType = 3;
}
else {
this.passType = 0;
}
// get length input for alphanum passwords
this.lengthChars = parseInt(sliderLength.value);
// get options
this.lower = chkLower.checked;
this.upper = chkUpper.checked;
this.digits = chkDigits.checked;
this.punct = chkPunct.checked;
this._all = chkAll.checked;
// get length input for mnemonic
this.lengthWords = parseInt(sliderWords.value);
this.whitespace = chkWhite.checked;
// get length and options for hex
this.hexLen = parseInt(sliderLenHex.value);
if (chkHexLenType.checked == true) {
this.hexLenType = "bytes";
}
else if (chkHexLenType.checked == false) {
this.hexLenType = "chars";
}
this.hexIdent = chkHexIdent.checked;
}
}
// tabs element
const tabs = document.getElementsByClassName("tablinks");
const btnTraditional = tabs[0];
const btnMnemonic = tabs[1];
const btnHexadecimal = tabs[2];
// "traditional" HTML elements
const sliderLength = <HTMLInputElement>document.getElementById("sliderLength");
const sliderValueLength = <HTMLInputElement>document.getElementById("sliderValueLength");
// checkboxes traditional
const chkAll = <HTMLInputElement>document.getElementById("chkAll");
const chkLower = <HTMLInputElement>document.getElementById("chkLower");
const chkUpper = <HTMLInputElement>document.getElementById("chkUpper");
const chkDigits = <HTMLInputElement>document.getElementById("chkDigits");
const chkPunct = <HTMLInputElement>document.getElementById("chkPunct");
// "mnemonic" HTML elements
// words range slider
const sliderWords = <HTMLInputElement>document.getElementById("sliderWords");
const sliderValueWords = <HTMLOutputElement>document.getElementById("sliderValueWords");
const chkWhite = <HTMLInputElement>document.getElementById("chkWhite");
// length range slider
const sliderLenHex = <HTMLInputElement>document.getElementById("sliderLenHex");
const sliderValueLenHex = <HTMLOutputElement>document.getElementById("sliderValueLenHex");
// "hexadecimal" HTML elements
const chkHexLenType = <HTMLInputElement>document.getElementById("chkLenType");
const chkHexIdent = <HTMLInputElement>document.getElementById("chkIdent");
/* -----------------
traditional password
----------------- */
// length range slider
sliderValueLength.innerHTML = (<HTMLInputElement>sliderLength).value; // Display the default slider value
// Update the current slider value (each time you drag the slider handle)
sliderLength.oninput = function() {
sliderValueLength.innerHTML = (<HTMLInputElement>this).value;
}
// checkboxes disabled
chkAll.addEventListener("change", function() {
if (this.checked) {
disableCheckboxes();
}
else {
enableCheckboxes();
}
});
chkLower.addEventListener("change", function() {
if (this.checked) {
disableCheckboxes();
}
else {
enableCheckboxes();
}
});
chkUpper.addEventListener("change", function() {
if (this.checked) {
disableCheckboxes();
}
else {
enableCheckboxes();
}
});
chkDigits.addEventListener("change", function() {
if (this.checked) {
disableCheckboxes();
}
else {
enableCheckboxes();
}
});
chkPunct.addEventListener("change", function() {
if (this.checked) {
disableCheckboxes();
}
else {
enableCheckboxes();
}
});
// disable other checkboxes
function disableCheckboxes() {
if (chkAll.checked == true) {
chkLower.setAttribute("disabled", ""); // set attribute to "true"
chkUpper.setAttribute("disabled", "");
chkDigits.setAttribute("disabled", "");
chkPunct.setAttribute("disabled", "");
}
else if (chkLower.checked == true || chkUpper.checked == true || chkDigits.checked == true || chkPunct.checked == true) {
chkAll.setAttribute("disabled", "");
}
}
// enable checkboxes again
function enableCheckboxes() {
if (chkAll.checked == false && chkAll.disabled == false) {
chkLower.removeAttribute("disabled");
chkUpper.removeAttribute("disabled");
chkDigits.removeAttribute("disabled");
chkPunct.removeAttribute("disabled");
}
else if (chkLower.checked == false && chkUpper.checked == false && chkDigits.checked == false && chkPunct.checked == false) {
chkAll.removeAttribute("disabled");
}
}
/* -----------------
mnemonic password
----------------- */
sliderValueWords.innerHTML = sliderWords.value; // Display the default slider value
// Update the current slider value (each time you drag the slider handle)
sliderWords.oninput = function() {
sliderValueWords.innerHTML = (<HTMLInputElement>this).value;
}
chkWhite.click(); // activated by default
/* -----------------
hex password
----------------- */
sliderValueLenHex.innerHTML = sliderLenHex.value; // Display the default slider value
// Update the current slider value (each time you drag the slider handle)
sliderLenHex.oninput = function() {
sliderValueLenHex.innerHTML = (<HTMLInputElement>this).value;
}
chkHexIdent.click(); // activated by default (0x...)
// ---------------
// general buttons
// ---------------
// button reset
const btnReset = <HTMLButtonElement>document.getElementById("btnReset");
btnReset.addEventListener("click", reset);
// button generate
const btnGen = <HTMLButtonElement>document.getElementById("btn-passgen");
btnGen.addEventListener("click", generatePassword);
// button copy
const btnCopy = <HTMLButtonElement>document.getElementById("btn-copy");
btnCopy.addEventListener("click", copyPwdToClipboard);
// output
const outField = <HTMLInputElement>document.getElementById("outField");
// create PassGen object on site load
const passGen = new PassGen();
// button "generate" (password) clicked
// get password and update output field
function generatePassword() {
// get password
let password = passGen.genPass();
// update password (output) field
if (password == "") {
// error: no option selected
//outField.style.backgroundColor("red");
outField.value = "Please select at least one option.";
}
else {
//outField.style.backgroundColor("#EFEFEF");
outField.value = password;
}
}
// button "randomize" (only for traditional passwords)
const btnRand = <HTMLButtonElement>document.getElementById('btn-rand');
// get a random number between min & max, both inclusive
function getRandInt(min: number, max: number) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
btnRand.addEventListener('click', function() {
// first reset everything
btnReset.click();
// set random slider number between 4 and 32
sliderLength.value = getRandInt(4, 32).toString();
sliderValueLength.innerHTML = sliderLength.value;
// select "ALL" with (almost) 25% prob
if (Math.random() < 0.2 ? true : false) {
chkAll.click();
}
else {
// determine which other options to activate with (almost) 50% prob
if (Math.random() < 0.5 ? true : false) {
chkLower.click();
}
if (Math.random() < 0.5 ? true : false) {
chkUpper.click();
}
if (Math.random() < 0.5 ? true : false) {
chkDigits.click();
}
if (Math.random() < 0.5 ? true : false) {
chkPunct.click();
}
}
});
// button "reset"
function reset() {
// reset range length slider
sliderLength.value = "12";
// also update output value
sliderValueLength.innerHTML = sliderLength.value;
// uncheck checkbox if checked
if (chkAll.checked == true) {
chkAll.click();
}
if (chkLower.checked == true) {
chkLower.click();
}
if (chkUpper.checked == true) {
chkUpper.click();
}
if (chkDigits.checked == true) {
chkDigits.click();
}
if (chkPunct.checked == true) {
chkPunct.click();
}
// reset words slider
sliderWords.value = "3";
sliderValueWords.innerHTML = sliderWords.value;
// check box if unchecked
if (chkWhite.checked == false) {
chkWhite.click();
}
// hex
// default length of 16 chars
sliderLenHex.value = "16";
sliderValueLenHex.innerHTML = sliderLenHex.value;
// defaults to length given in chars (unchecked)
if (chkHexLenType.checked == true) {
chkHexLenType.click();
}
// defaults to prefix (checked)
if (chkHexIdent.checked == false) {
chkHexIdent.click();
}
// reset output field
outField.value = "";
}
// copy generated password to clipboard
// from https://www.30secondsofcode.org/articles/s/copy-text-to-clipboard-with-javascript
const copyToClipboard = (str: string) => {
if (navigator && navigator.clipboard && navigator.clipboard.writeText)
return navigator.clipboard.writeText(str);
return Promise.reject('The Clipboard API is not available.');
};
function copyPwdToClipboard() {
// get password from outField
let password = outField.value;
// if content is not a password
if (password == "" || password == "Please select at least one option." || password == "Generate a password first!") {
outField.value = "Generate a password first!";
}
else {
copyToClipboard(password);
// show popper notification
showPopper();
}
}
// site tabs js
function openTab(evt: any, name: any) {
// Declare all variables
let i: number;
let tabcontent, tablinks;
// Get all elements with class="tabcontent" and hide them
tabcontent = <HTMLCollectionOf<HTMLElement>>document.getElementsByClassName("tabcontent");
for (i = 0; i < tabcontent.length; i++) {
tabcontent[i].style.display = "none";
}
// Get all elements with class="tablinks" and remove the class "active"
tablinks = document.getElementsByClassName("tablinks");
for (i = 0; i < tablinks.length; i++) {
tablinks[i].className = tablinks[i].className.replace(" active", "");
}
// Show the current tab, and add an "active" class to the button that opened the tab
document.getElementById(name).style.display = "block";
evt.currentTarget.className += " active";
}
// popper js
// const button = document.getElementById("btn-passgen"); // gets button above
const tooltip = document.getElementById("tooltip");
// @ts-ignore: Cannot find name 'Popper'
const popperInstance = Popper.createPopper(btnCopy, tooltip, {
modifiers: [
{
name: 'offset',
options: {
offset: [0, 8],
},
},
],
});
function showPopper() {
// Make the tooltip visible
tooltip.setAttribute('data-show', '');
// Enable the event listeners
popperInstance.setOptions((options: any) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: true },
],
}));
// Update its position
// We need to tell Popper to update the tooltip position
// after we show the tooltip, otherwise it will be incorrect
popperInstance.update();
}
function hidePopper() {
// Hide the tooltip
tooltip.removeAttribute('data-show');
// Disable the event listeners
popperInstance.setOptions((options: any) => ({
...options,
modifiers: [
...options.modifiers,
{ name: 'eventListeners', enabled: false },
],
}));
}
// const showEvents = ['focus'];
const hideEvents = ['blur'];
/*
showEvents.forEach((event) => {
btnCopy.addEventListener(event, showPopper);
});
*/
hideEvents.forEach((event) => {
btnCopy.addEventListener(event, hidePopper);
});
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
// add footer content into the footer element
const footer = document.getElementById('footer');
footer.innerHTML = `
<div class="footer-left">Virtual privacy<br>
Right to freedom<br>
</div>
<div class="footer-right">
By <a onclick='openInNewTab("https://pbr.plus/")' class='link' style='color: #19376D;'>Philippe Braum</a><br>
v${
// @ts-ignore: Cannot find name 'siteVersion'
siteVersion
}
</div>
`;
// funtion: open link safely in new tab
const openInNewTab = (url: string) => {
const newWindow = window.open(url, '_blank', 'noopener,noreferrer');
if (newWindow) newWindow.opener = null;
}
// password check site functionality
const ratingsMappings = {
"numbers": ["VERY WEAK", "WEAK", "MEDIUM", "SECURE", "HIGHLY SECURE"],
"colors": ["red", "orange", "yellow", "lightgreen", "green"]
}
const passCheckInput = <HTMLInputElement>document.getElementById('check-password-input');
const progressbarContainer = <HTMLDivElement>document.getElementById('progressbar-container');
const ratingProgressbar = <HTMLDivElement>document.getElementById('progressbar-progress');
const ratingString = <HTMLSpanElement>document.getElementById('pass-check-rating-string');
const ratingTtsOnline = <HTMLSpanElement>document.getElementById('check-tts-online');
const ratingTtsOffline = <HTMLSpanElement>document.getElementById('check-tts-offline');
const crackTimes = <HTMLDivElement>document.getElementById('crack-times');
passCheckInput.addEventListener("input", () => {
crackTimes.style.display = "";
if (passCheckInput.value == "") {
ratingProgressbar.style.width = "0px";
ratingString.innerHTML = "";
crackTimes.style.display = "none";
}
else {
// @ts-ignore
let result = zxcvbn(passCheckInput.value);
ratingProgressbar.style.width = `${(progressbarContainer.offsetWidth / 5) * (result.score + 1)}px`;
ratingProgressbar.style.backgroundColor = ratingsMappings["colors"][result.score];
ratingString.innerHTML = ratingsMappings["numbers"][result.score];
ratingTtsOnline.innerHTML = result.crack_times_display["online_no_throttling_10_per_second"];
ratingTtsOffline.innerHTML = result.crack_times_display["offline_slow_hashing_1e4_per_second"];
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment