Initial commit
This commit is contained in:
commit
f9c8b6f016
34 changed files with 15853 additions and 0 deletions
8
.gitattributes
vendored
Normal file
8
.gitattributes
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
/apache export-ignore
|
||||
/cache export-ignore
|
||||
/tests export-ignore
|
||||
/changelog.md export-ignore
|
||||
/docker-compose.yml export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/phpunit.xml export-ignore
|
||||
/.scrutinizer.yml export-ignore
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
/cache/
|
||||
/vendor/
|
||||
/cache/
|
35
.scrutinizer.yml
Normal file
35
.scrutinizer.yml
Normal file
|
@ -0,0 +1,35 @@
|
|||
filter:
|
||||
excluded_paths: [tests/*]
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
remove_extra_empty_lines: true
|
||||
remove_php_closing_tag: true
|
||||
remove_trailing_whitespace: true
|
||||
fix_use_statements:
|
||||
remove_unused: true
|
||||
preserve_multiple: false
|
||||
preserve_blanklines: true
|
||||
order_alphabetically: true
|
||||
fix_php_opening_tag: true
|
||||
fix_linefeed: true
|
||||
fix_line_ending: true
|
||||
fix_identation_4spaces: true
|
||||
fix_doc_comments: true
|
||||
tools:
|
||||
external_code_coverage:
|
||||
timeout: 600
|
||||
runs: 3
|
||||
php_analyzer: true
|
||||
php_code_coverage: false
|
||||
php_code_sniffer:
|
||||
config:
|
||||
standard: PSR2
|
||||
filter:
|
||||
paths: ['src']
|
||||
php_loc:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests]
|
||||
php_cpd:
|
||||
enabled: true
|
||||
excluded_dirs: [vendor, tests]
|
10
.travis.yml
Normal file
10
.travis.yml
Normal file
|
@ -0,0 +1,10 @@
|
|||
language: php
|
||||
php:
|
||||
- 5.6
|
||||
- 5.5
|
||||
- 5.4
|
||||
- hhvm
|
||||
|
||||
before_script:
|
||||
- composer self-update
|
||||
- composer install
|
32
CONTRIBUTING.md
Normal file
32
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,32 @@
|
|||
# Contributing
|
||||
|
||||
Contributions are **welcome** and will be fully **credited**.
|
||||
|
||||
I accept contributions via Pull Requests on [Github](https://github.com/raphiz/passwordcards).
|
||||
|
||||
|
||||
## Pull Requests
|
||||
|
||||
- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).
|
||||
|
||||
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
|
||||
|
||||
- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date.
|
||||
|
||||
- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option.
|
||||
|
||||
- **Create feature branches** - Don't ask us to pull from your master branch.
|
||||
|
||||
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
|
||||
|
||||
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
|
||||
|
||||
|
||||
## Running Tests
|
||||
|
||||
``` bash
|
||||
$ composer test
|
||||
```
|
||||
|
||||
|
||||
**Happy coding**!
|
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
|
@ -0,0 +1,21 @@
|
|||
# The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Raphael Zimmermann <mister.norbert ät gmail.com>
|
||||
|
||||
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
> of this software and associated documentation files (the "Software"), to deal
|
||||
> in the Software without restriction, including without limitation the rights
|
||||
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
> copies of the Software, and to permit persons to whom the Software is
|
||||
> furnished to do so, subject to the following conditions:
|
||||
>
|
||||
> The above copyright notice and this permission notice shall be included in
|
||||
> all copies or substantial portions of the Software.
|
||||
>
|
||||
> THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
> THE SOFTWARE.
|
29
README.md
Normal file
29
README.md
Normal file
|
@ -0,0 +1,29 @@
|
|||
# passwordcards
|
||||
|
||||
[![Latest Version](https://img.shields.io/github/release/raphiz/passwordcards.svg?style=flat-square)](https://github.com/raphiz/passwordcards/releases)
|
||||
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.md)
|
||||
[![Build Status](https://img.shields.io/travis/raphiz/passwordcards/master.svg?style=flat-square)](https://travis-ci.org/raphiz/passwordcards)
|
||||
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/raphiz/passwordcards/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/raphiz/passwordcards/?branch=master)
|
||||
[![Code Climate](https://codeclimate.com/github/raphiz/passwordcards/badges/gpa.svg)](https://codeclimate.com/github/raphiz/passwordcards)
|
||||
[![Test Coverage](https://codeclimate.com/github/raphiz/passwordcards/badges/coverage.svg)](https://codeclimate.com/github/raphiz/passwordcards)
|
||||
This is where your description should go. Try and limit it to a paragraph or two, and maybe throw in a mention of what
|
||||
PSRs you support to avoid any confusion with users and contributors.
|
||||
|
||||
## Contributing
|
||||
|
||||
Please see [CONTRIBUTING](CONTRIBUTING.md) for details.
|
||||
|
||||
## Security
|
||||
|
||||
If you discover any security related issues, please email mister.norbert ät gmail.com instead of using the issue tracker.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
The MIT License (MIT). Please see [License File](LICENSE.md) for more information.
|
||||
|
||||
|
||||
## To be done:
|
||||
add
|
||||
* Analysis via https://insight.sensiolabs.com/
|
||||
* make .htaccess that only allows requests to /resources OR /index.php!
|
2
apache/Dockerfile
Normal file
2
apache/Dockerfile
Normal file
|
@ -0,0 +1,2 @@
|
|||
FROM php:5.6-apache
|
||||
COPY php.ini /usr/local/etc/php/
|
1938
apache/php.ini
Normal file
1938
apache/php.ini
Normal file
File diff suppressed because it is too large
Load diff
2
changelog.md
Normal file
2
changelog.md
Normal file
|
@ -0,0 +1,2 @@
|
|||
## [Unreleased][unreleased]
|
||||
- Initial Release
|
23
composer.json
Normal file
23
composer.json
Normal file
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "raphiz/passwordcards",
|
||||
"require": {
|
||||
"tecnick.com/tcpdf": "6.2.6",
|
||||
"rain/raintpl": "3.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "4.5.0"
|
||||
},
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Raphael Zimmermann",
|
||||
"email": "mister.norbert@gmail.com"
|
||||
}
|
||||
],
|
||||
"autoload": {
|
||||
"psr-4": { "raphiz\\passwordcards\\": "src/" }
|
||||
},
|
||||
"scripts": {
|
||||
"test": "vendor/bin/phpunit"
|
||||
}
|
||||
}
|
1074
composer.lock
generated
Normal file
1074
composer.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
6
docker-compose.yml
Normal file
6
docker-compose.yml
Normal file
|
@ -0,0 +1,6 @@
|
|||
web:
|
||||
build: apache/
|
||||
volumes:
|
||||
- ./:/var/www/html:rw
|
||||
ports:
|
||||
- "8000:80"
|
53
index.php
Normal file
53
index.php
Normal file
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
namespace raphiz\passwordcards;
|
||||
|
||||
require_once 'vendor/autoload.php';
|
||||
use \Rain\Tpl;
|
||||
|
||||
if (!RequestUtils::isPost()) {
|
||||
// Render template
|
||||
Tpl::configure(
|
||||
array(
|
||||
"tpl_dir" => __DIR__ . "/resources/",
|
||||
)
|
||||
);
|
||||
$tpl = new Tpl;
|
||||
$tpl->draw('index');
|
||||
} else {
|
||||
// Parse request
|
||||
$pattern = RequestUtils::parsePattern();
|
||||
$keyboardLayout = RequestUtils::parseKeyboardLayout();
|
||||
$seed = RequestUtils::parseSeed();
|
||||
$text = RequestUtils::parseText();
|
||||
$primary = RequestUtils::parsePrimaryColor();
|
||||
$secondary = RequestUtils::parseSecondaryColor();
|
||||
$spaceBarSize = RequestUtils::parseSpacebarSize();
|
||||
|
||||
// Setup configuration
|
||||
$cfg = new Configuration($seed, $pattern, $keyboardLayout, $spaceBarSize, $text, $primary, $secondary);
|
||||
$creator = new CardCreator($cfg);
|
||||
|
||||
// Load SVG templates
|
||||
$front_template = $creator->getSvgTemplate('simple_back');
|
||||
$back_template = $creator->getSvgTemplate('simple_front');
|
||||
|
||||
// Render SVG into tempfiles
|
||||
$front = $creator->renderIntoTempfile($front_template);
|
||||
$back = $creator->renderIntoTempfile($back_template);
|
||||
|
||||
// Render the PDF
|
||||
$doc = PDFRenderer::render($front, $back);
|
||||
|
||||
// Prepare response PDF file header
|
||||
RequestUtils::preparePdfHeader(strlen($doc));
|
||||
|
||||
// Ignore user abort to cleanup afterwards
|
||||
ignore_user_abort(true);
|
||||
|
||||
// Strem the PDF
|
||||
echo $doc;
|
||||
|
||||
// Cleanup temporary SVG images
|
||||
unlink($back);
|
||||
unlink($front);
|
||||
}
|
19
phpunit.xml
Normal file
19
phpunit.xml
Normal file
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit backupGlobals="false"
|
||||
backupStaticAttributes="false"
|
||||
colors="true"
|
||||
convertErrorsToExceptions="true"
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false"
|
||||
bootstrap="./vendor/autoload.php"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="tests">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
BIN
resources/cards.png
Normal file
BIN
resources/cards.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
69
resources/css/main.css
Normal file
69
resources/css/main.css
Normal file
|
@ -0,0 +1,69 @@
|
|||
.header {
|
||||
margin-top: 3em;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.configure {
|
||||
text-align: center;
|
||||
margin-top: 30px;
|
||||
}
|
||||
|
||||
#advancedOptionsLabel {
|
||||
color:#1EAEDB;
|
||||
cursor: pointer;
|
||||
}
|
||||
#advancedOptions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#hideMoreOptions {
|
||||
display: none;
|
||||
}
|
||||
.hidden,
|
||||
input.hidden{
|
||||
display: none;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
#with-numbers:checked + .label-with-numbers,
|
||||
#with-lower:checked + .label-with-lower,
|
||||
#with-upper:checked + .label-with-upper,
|
||||
#with-symbols:checked + .label-with-symbols,
|
||||
#with-space:checked + .label-with-space,
|
||||
#with-other:checked + .label-with-other
|
||||
{
|
||||
color: #FFF;
|
||||
background-color: #33C3F0;
|
||||
border-color: #33C3F0;
|
||||
}
|
||||
|
||||
.tooltip{
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tooltip:hover:after{
|
||||
background: #333;
|
||||
background: rgba(0,0,0,.8);
|
||||
border-radius: 5px;
|
||||
bottom: 46px;
|
||||
color: #fff;
|
||||
content: attr(title);
|
||||
text-transform: none;
|
||||
left: 20%;
|
||||
padding: 5px 15px;
|
||||
position: absolute;
|
||||
z-index: 98;
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.tooltip:hover:before{
|
||||
border: solid;
|
||||
border-color: #333 transparent;
|
||||
border-width: 6px 6px 0 6px;
|
||||
bottom: 40px;
|
||||
content: "";
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
}
|
427
resources/css/normalize.css
vendored
Normal file
427
resources/css/normalize.css
vendored
Normal file
|
@ -0,0 +1,427 @@
|
|||
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
|
||||
|
||||
/**
|
||||
* 1. Set default font family to sans-serif.
|
||||
* 2. Prevent iOS text size adjust after orientation change, without disabling
|
||||
* user zoom.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default margin.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
||||
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
||||
* and Firefox.
|
||||
* Correct `block` display not defined for `main` in IE 11.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
menu,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `inline-block` display not defined in IE 8/9.
|
||||
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `[hidden]` styling not present in IE 8/9/10.
|
||||
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
|
||||
*/
|
||||
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Links
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background color from active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability when focused and also mouse hovered in all browsers.
|
||||
*/
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in Safari and Chrome.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address variable `h1` font-size and margin within `section` and `article`
|
||||
* contexts in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove border when inside `a` element in IE 8/9/10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct overflow not hidden in IE 9/10/11.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address margin not present in IE 8/9 and Safari.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address differences between Firefox and other browsers.
|
||||
*/
|
||||
|
||||
hr {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contain overflow in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address odd `em`-unit font size rendering in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
||||
* styling of `select`, unless a `border` property is set.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 1. Correct color not being inherited.
|
||||
* Known issue: affects color of disabled elements.
|
||||
* 2. Correct font properties not being inherited.
|
||||
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
color: inherit; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
button {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||
* All other form control elements do not inherit `text-transform` values.
|
||||
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
||||
* Correct `select` style inheritance in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Correct inability to style clickable `input` types in iOS.
|
||||
* 3. Improve usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
*/
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and border in Firefox 4+.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's recommended that you don't attempt to style these elements.
|
||||
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
||||
*
|
||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||
* 2. Remove excess padding in IE 8/9/10.
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
||||
* `font-size` values of the `input`, it causes the cursor style of the
|
||||
* decrement button to change from `default` to `text`.
|
||||
*/
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
||||
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
|
||||
* (include `-moz` to future-proof).
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
||||
* Safari (but not Chrome) clips the cancel button when the search input has
|
||||
* padding (and `textfield` appearance).
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default vertical scrollbar in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't inherit the `font-weight` (applied by a rule above).
|
||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
||||
*/
|
||||
|
||||
optgroup {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Tables
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
418
resources/css/skeleton.css
vendored
Normal file
418
resources/css/skeleton.css
vendored
Normal file
|
@ -0,0 +1,418 @@
|
|||
/*
|
||||
* Skeleton V2.0.4
|
||||
* Copyright 2014, Dave Gamache
|
||||
* www.getskeleton.com
|
||||
* Free to use under the MIT license.
|
||||
* http://www.opensource.org/licenses/mit-license.php
|
||||
* 12/29/2014
|
||||
*/
|
||||
|
||||
|
||||
/* Table of contents
|
||||
––––––––––––––––––––––––––––––––––––––––––––––––––
|
||||
- Grid
|
||||
- Base Styles
|
||||
- Typography
|
||||
- Links
|
||||
- Buttons
|
||||
- Forms
|
||||
- Lists
|
||||
- Code
|
||||
- Tables
|
||||
- Spacing
|
||||
- Utilities
|
||||
- Clearing
|
||||
- Media Queries
|
||||
*/
|
||||
|
||||
|
||||
/* Grid
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
.container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 960px;
|
||||
margin: 0 auto;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box; }
|
||||
.column,
|
||||
.columns {
|
||||
width: 100%;
|
||||
float: left;
|
||||
box-sizing: border-box; }
|
||||
|
||||
/* For devices larger than 400px */
|
||||
@media (min-width: 400px) {
|
||||
.container {
|
||||
width: 85%;
|
||||
padding: 0; }
|
||||
}
|
||||
|
||||
/* For devices larger than 550px */
|
||||
@media (min-width: 550px) {
|
||||
.container {
|
||||
width: 80%; }
|
||||
.column,
|
||||
.columns {
|
||||
margin-left: 4%; }
|
||||
.column:first-child,
|
||||
.columns:first-child {
|
||||
margin-left: 0; }
|
||||
|
||||
.one.column,
|
||||
.one.columns { width: 4.66666666667%; }
|
||||
.two.columns { width: 13.3333333333%; }
|
||||
.three.columns { width: 22%; }
|
||||
.four.columns { width: 30.6666666667%; }
|
||||
.five.columns { width: 39.3333333333%; }
|
||||
.six.columns { width: 48%; }
|
||||
.seven.columns { width: 56.6666666667%; }
|
||||
.eight.columns { width: 65.3333333333%; }
|
||||
.nine.columns { width: 74.0%; }
|
||||
.ten.columns { width: 82.6666666667%; }
|
||||
.eleven.columns { width: 91.3333333333%; }
|
||||
.twelve.columns { width: 100%; margin-left: 0; }
|
||||
|
||||
.one-third.column { width: 30.6666666667%; }
|
||||
.two-thirds.column { width: 65.3333333333%; }
|
||||
|
||||
.one-half.column { width: 48%; }
|
||||
|
||||
/* Offsets */
|
||||
.offset-by-one.column,
|
||||
.offset-by-one.columns { margin-left: 8.66666666667%; }
|
||||
.offset-by-two.column,
|
||||
.offset-by-two.columns { margin-left: 17.3333333333%; }
|
||||
.offset-by-three.column,
|
||||
.offset-by-three.columns { margin-left: 26%; }
|
||||
.offset-by-four.column,
|
||||
.offset-by-four.columns { margin-left: 34.6666666667%; }
|
||||
.offset-by-five.column,
|
||||
.offset-by-five.columns { margin-left: 43.3333333333%; }
|
||||
.offset-by-six.column,
|
||||
.offset-by-six.columns { margin-left: 52%; }
|
||||
.offset-by-seven.column,
|
||||
.offset-by-seven.columns { margin-left: 60.6666666667%; }
|
||||
.offset-by-eight.column,
|
||||
.offset-by-eight.columns { margin-left: 69.3333333333%; }
|
||||
.offset-by-nine.column,
|
||||
.offset-by-nine.columns { margin-left: 78.0%; }
|
||||
.offset-by-ten.column,
|
||||
.offset-by-ten.columns { margin-left: 86.6666666667%; }
|
||||
.offset-by-eleven.column,
|
||||
.offset-by-eleven.columns { margin-left: 95.3333333333%; }
|
||||
|
||||
.offset-by-one-third.column,
|
||||
.offset-by-one-third.columns { margin-left: 34.6666666667%; }
|
||||
.offset-by-two-thirds.column,
|
||||
.offset-by-two-thirds.columns { margin-left: 69.3333333333%; }
|
||||
|
||||
.offset-by-one-half.column,
|
||||
.offset-by-one-half.columns { margin-left: 52%; }
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Base Styles
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
/* NOTE
|
||||
html is set to 62.5% so that all the REM measurements throughout Skeleton
|
||||
are based on 10px sizing. So basically 1.5rem = 15px :) */
|
||||
html {
|
||||
font-size: 62.5%; }
|
||||
body {
|
||||
font-size: 1.5em; /* currently ems cause chrome bug misinterpreting rems on body element */
|
||||
line-height: 1.6;
|
||||
font-weight: 400;
|
||||
font-family: "Raleway", "HelveticaNeue", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
color: #222; }
|
||||
|
||||
|
||||
/* Typography
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
margin-top: 0;
|
||||
margin-bottom: 2rem;
|
||||
font-weight: 300; }
|
||||
h1 { font-size: 4.0rem; line-height: 1.2; letter-spacing: -.1rem;}
|
||||
h2 { font-size: 3.6rem; line-height: 1.25; letter-spacing: -.1rem; }
|
||||
h3 { font-size: 3.0rem; line-height: 1.3; letter-spacing: -.1rem; }
|
||||
h4 { font-size: 2.4rem; line-height: 1.35; letter-spacing: -.08rem; }
|
||||
h5 { font-size: 1.8rem; line-height: 1.5; letter-spacing: -.05rem; }
|
||||
h6 { font-size: 1.5rem; line-height: 1.6; letter-spacing: 0; }
|
||||
|
||||
/* Larger than phablet */
|
||||
@media (min-width: 550px) {
|
||||
h1 { font-size: 5.0rem; }
|
||||
h2 { font-size: 4.2rem; }
|
||||
h3 { font-size: 3.6rem; }
|
||||
h4 { font-size: 3.0rem; }
|
||||
h5 { font-size: 2.4rem; }
|
||||
h6 { font-size: 1.5rem; }
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0; }
|
||||
|
||||
|
||||
/* Links
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
a {
|
||||
color: #1EAEDB; }
|
||||
a:hover {
|
||||
color: #0FA0CE; }
|
||||
|
||||
|
||||
/* Buttons
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
.button,
|
||||
button,
|
||||
input[type="submit"],
|
||||
input[type="reset"],
|
||||
input[type="button"] {
|
||||
display: inline-block;
|
||||
height: 38px;
|
||||
padding: 0 30px;
|
||||
color: #555;
|
||||
text-align: center;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 38px;
|
||||
letter-spacing: .1rem;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
white-space: nowrap;
|
||||
background-color: transparent;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #bbb;
|
||||
cursor: pointer;
|
||||
box-sizing: border-box; }
|
||||
.button:hover,
|
||||
button:hover,
|
||||
input[type="submit"]:hover,
|
||||
input[type="reset"]:hover,
|
||||
input[type="button"]:hover,
|
||||
.button:focus,
|
||||
button:focus,
|
||||
input[type="submit"]:focus,
|
||||
input[type="reset"]:focus,
|
||||
input[type="button"]:focus {
|
||||
color: #333;
|
||||
border-color: #888;
|
||||
outline: 0; }
|
||||
.button.button-primary,
|
||||
button.button-primary,
|
||||
input[type="submit"].button-primary,
|
||||
input[type="reset"].button-primary,
|
||||
input[type="button"].button-primary {
|
||||
color: #FFF;
|
||||
background-color: #33C3F0;
|
||||
border-color: #33C3F0; }
|
||||
.button.button-primary:hover,
|
||||
button.button-primary:hover,
|
||||
input[type="submit"].button-primary:hover,
|
||||
input[type="reset"].button-primary:hover,
|
||||
input[type="button"].button-primary:hover,
|
||||
.button.button-primary:focus,
|
||||
button.button-primary:focus,
|
||||
input[type="submit"].button-primary:focus,
|
||||
input[type="reset"].button-primary:focus,
|
||||
input[type="button"].button-primary:focus {
|
||||
color: #FFF;
|
||||
background-color: #1EAEDB;
|
||||
border-color: #1EAEDB; }
|
||||
|
||||
|
||||
/* Forms
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
input[type="email"],
|
||||
input[type="number"],
|
||||
input[type="search"],
|
||||
input[type="text"],
|
||||
input[type="tel"],
|
||||
input[type="url"],
|
||||
input[type="password"],
|
||||
textarea,
|
||||
select {
|
||||
height: 38px;
|
||||
padding: 6px 10px; /* The 6px vertically centers text on FF, ignored by Webkit */
|
||||
background-color: #fff;
|
||||
border: 1px solid #D1D1D1;
|
||||
border-radius: 4px;
|
||||
box-shadow: none;
|
||||
box-sizing: border-box; }
|
||||
/* Removes awkward default styles on some inputs for iOS */
|
||||
input[type="email"],
|
||||
input[type="number"],
|
||||
input[type="search"],
|
||||
input[type="text"],
|
||||
input[type="tel"],
|
||||
input[type="url"],
|
||||
input[type="password"],
|
||||
textarea {
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
appearance: none; }
|
||||
textarea {
|
||||
min-height: 65px;
|
||||
padding-top: 6px;
|
||||
padding-bottom: 6px; }
|
||||
input[type="email"]:focus,
|
||||
input[type="number"]:focus,
|
||||
input[type="search"]:focus,
|
||||
input[type="text"]:focus,
|
||||
input[type="tel"]:focus,
|
||||
input[type="url"]:focus,
|
||||
input[type="password"]:focus,
|
||||
textarea:focus,
|
||||
select:focus {
|
||||
border: 1px solid #33C3F0;
|
||||
outline: 0; }
|
||||
label,
|
||||
legend {
|
||||
display: block;
|
||||
margin-bottom: .5rem;
|
||||
font-weight: 600; }
|
||||
fieldset {
|
||||
padding: 0;
|
||||
border-width: 0; }
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
display: inline; }
|
||||
label > .label-body {
|
||||
display: inline-block;
|
||||
margin-left: .5rem;
|
||||
font-weight: normal; }
|
||||
|
||||
|
||||
/* Lists
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
ul {
|
||||
list-style: circle inside; }
|
||||
ol {
|
||||
list-style: decimal inside; }
|
||||
ol, ul {
|
||||
padding-left: 0;
|
||||
margin-top: 0; }
|
||||
ul ul,
|
||||
ul ol,
|
||||
ol ol,
|
||||
ol ul {
|
||||
margin: 1.5rem 0 1.5rem 3rem;
|
||||
font-size: 90%; }
|
||||
li {
|
||||
margin-bottom: 1rem; }
|
||||
|
||||
|
||||
/* Code
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
code {
|
||||
padding: .2rem .5rem;
|
||||
margin: 0 .2rem;
|
||||
font-size: 90%;
|
||||
white-space: nowrap;
|
||||
background: #F1F1F1;
|
||||
border: 1px solid #E1E1E1;
|
||||
border-radius: 4px; }
|
||||
pre > code {
|
||||
display: block;
|
||||
padding: 1rem 1.5rem;
|
||||
white-space: pre; }
|
||||
|
||||
|
||||
/* Tables
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
th,
|
||||
td {
|
||||
padding: 12px 15px;
|
||||
text-align: left;
|
||||
border-bottom: 1px solid #E1E1E1; }
|
||||
th:first-child,
|
||||
td:first-child {
|
||||
padding-left: 0; }
|
||||
th:last-child,
|
||||
td:last-child {
|
||||
padding-right: 0; }
|
||||
|
||||
|
||||
/* Spacing
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
button,
|
||||
.button {
|
||||
margin-bottom: 1rem; }
|
||||
input,
|
||||
textarea,
|
||||
select,
|
||||
fieldset {
|
||||
margin-bottom: 1.5rem; }
|
||||
pre,
|
||||
blockquote,
|
||||
dl,
|
||||
figure,
|
||||
table,
|
||||
p,
|
||||
ul,
|
||||
ol,
|
||||
form {
|
||||
margin-bottom: 2.5rem; }
|
||||
|
||||
|
||||
/* Utilities
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
.u-full-width {
|
||||
width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.u-max-full-width {
|
||||
max-width: 100%;
|
||||
box-sizing: border-box; }
|
||||
.u-pull-right {
|
||||
float: right; }
|
||||
.u-pull-left {
|
||||
float: left; }
|
||||
|
||||
|
||||
/* Misc
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
hr {
|
||||
margin-top: 3rem;
|
||||
margin-bottom: 3.5rem;
|
||||
border-width: 0;
|
||||
border-top: 1px solid #E1E1E1; }
|
||||
|
||||
|
||||
/* Clearing
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
|
||||
/* Self Clearing Goodness */
|
||||
.container:after,
|
||||
.row:after,
|
||||
.u-cf {
|
||||
content: "";
|
||||
display: table;
|
||||
clear: both; }
|
||||
|
||||
|
||||
/* Media Queries
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– */
|
||||
/*
|
||||
Note: The best way to structure the use of media queries is to create the queries
|
||||
near the relevant code. For example, if you wanted to change the styles for buttons
|
||||
on small devices, paste the mobile query code up in the buttons section and style it
|
||||
there.
|
||||
*/
|
||||
|
||||
|
||||
/* Larger than mobile */
|
||||
@media (min-width: 400px) {}
|
||||
|
||||
/* Larger than phablet (also point when grid becomes active) */
|
||||
@media (min-width: 550px) {}
|
||||
|
||||
/* Larger than tablet */
|
||||
@media (min-width: 750px) {}
|
||||
|
||||
/* Larger than desktop */
|
||||
@media (min-width: 1000px) {}
|
||||
|
||||
/* Larger than Desktop HD */
|
||||
@media (min-width: 1200px) {}
|
67
resources/css/tinycolorpicker.css
Normal file
67
resources/css/tinycolorpicker.css
Normal file
|
@ -0,0 +1,67 @@
|
|||
/* COLORPICKER 3 EXAMPLE */
|
||||
.colorPicker
|
||||
{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
position: relative;
|
||||
clear: both;
|
||||
margin: 0 auto 20px;
|
||||
}
|
||||
|
||||
.colorPicker .track {
|
||||
background: #EFEFEF url(../text-color.png) no-repeat 50% 50%;
|
||||
height: 150px;
|
||||
width: 150px;
|
||||
padding: 10px;
|
||||
position: absolute;
|
||||
cursor: crosshair;
|
||||
float: left;
|
||||
left: -71px;
|
||||
top: -71px;
|
||||
display: none;
|
||||
border: 1px solid #ccc;
|
||||
z-index: 10;
|
||||
-webkit-border-radius: 150px;
|
||||
-moz-border-radius: 150px;
|
||||
border-radius: 150px;
|
||||
|
||||
}
|
||||
|
||||
.colorPicker .color {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
padding: 1px;
|
||||
border: 1px solid #ccc;
|
||||
display: block;
|
||||
position: relative;
|
||||
z-index: 11;
|
||||
background-color: #EFEFEF;
|
||||
-webkit-border-radius: 27px;
|
||||
-moz-border-radius: 27px;
|
||||
border-radius: 27px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.colorPicker .colorInner {
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
-webkit-border-radius: 27px;
|
||||
-moz-border-radius: 27px;
|
||||
border-radius: 27px;
|
||||
}
|
||||
|
||||
.colorPicker .dropdown {
|
||||
list-style: none;
|
||||
display: none;
|
||||
width: 27px;
|
||||
position: absolute;
|
||||
top: 28px;
|
||||
border: 1px solid #ccc;
|
||||
left: 0;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
.colorPicker .dropdown li{
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
}
|
BIN
resources/favicon.png
Normal file
BIN
resources/favicon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
136
resources/index.html
Normal file
136
resources/index.html
Normal file
|
@ -0,0 +1,136 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
|
||||
<!-- Basic Page Needs
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<meta charset="utf-8">
|
||||
<title>Password Card Generator</title>
|
||||
<meta name="description" content="Password Card Generator">
|
||||
<meta name="author" content="Raphael Zimmermann">
|
||||
|
||||
<!-- Mobile Specific Metas
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- FONT
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<link href="//fonts.googleapis.com/css?family=Raleway:400,300,600" rel="stylesheet" type="text/css">
|
||||
|
||||
<!-- CSS
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<link rel="stylesheet" href="resources/css/normalize.css">
|
||||
<link rel="stylesheet" href="resources/css/skeleton.css">
|
||||
<link rel="stylesheet" href="resources/css/tinycolorpicker.css">
|
||||
<link rel="stylesheet" href="resources/css/main.css">
|
||||
|
||||
<!-- Favicon
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<link rel="icon" type="image/png" href="resources/favicon.png">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Primary Page Layout
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<h1>Password Card Generator</h1>
|
||||
<p>
|
||||
This website allows you to generate customized password cards in
|
||||
the spirit of <a href="https://www.qwertycards.com" target="_blank">Qwertycards.com</a>
|
||||
</p>
|
||||
<p>
|
||||
If you like the concept, please buy a card from their <a href="https://www.qwertycards.com" target="_blank">website</a>
|
||||
</p>
|
||||
<img src="resources/cards.png" width="100%">
|
||||
</div>
|
||||
|
||||
<div class="configure">
|
||||
<h1>Generate a new card</h1>
|
||||
<p>Pick the characters you want to use</p>
|
||||
<form action="" method="POST" accept-charset="ISO-8859-15">
|
||||
<div class="row">
|
||||
<input type="checkbox" name="with-numbers" id="with-numbers" class="hidden" autocomplete="off" checked>
|
||||
<label for="with-numbers" class="label-with-numbers button tooltip" title="0123456789">numbers</label>
|
||||
|
||||
<input type="checkbox" name="with-lower" id="with-lower" class="hidden" autocomplete="off" checked>
|
||||
<label for="with-lower" class="label-with-lower button tooltip" title="abcdefghijklmnopqrstuvwxyz">lower case</label>
|
||||
|
||||
<input type="checkbox" name="with-upper" id="with-upper" class="hidden" autocomplete="off" checked>
|
||||
<label for="with-upper" class="label-with-upper button tooltip" title="ABCDEFGHIJKLMNOPQRSTUVWXYZ">upper case</label>
|
||||
|
||||
<input type="checkbox" name="with-symbols" id="with-symbols" class="hidden" autocomplete="off" checked>
|
||||
<label for="with-symbols" class="label-with-symbols button tooltip" title="!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~">symbols</label>
|
||||
|
||||
<input type="checkbox" name="with-space" id="with-space" class="hidden" autocomplete="off" >
|
||||
<label for="with-space" class="label-with-space button">space</label>
|
||||
|
||||
<input type="checkbox" name="with-other" id="with-other" class="hidden" autocomplete="off" >
|
||||
<label for="with-other" class="label-with-other button tooltip" title="anything else?">other</label>
|
||||
|
||||
</div>
|
||||
<div class="row" style="display: none; ">
|
||||
<input type="text" id="other-chars" name="other-chars" placeholder="Place other symbols in here" maxlength="20" autocomplete="off"/>
|
||||
</div>
|
||||
|
||||
<div class="row" style="margin-top: 30px;">
|
||||
<p>What's your Keyboard layout?</p>
|
||||
<select type="text" name="keyboardlayout">
|
||||
<option value="qwerty">QWERTY</option>
|
||||
<option value="qwertz">QWERTZ</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="row" style="margin-top: 30px;">
|
||||
<p>This text goes on the back of your card</p>
|
||||
<input type="text" name="msg" placeholder="For Work" maxlength="20" autocomplete="off">
|
||||
</div>
|
||||
|
||||
<div class="row" style="margin-top: 30px;">
|
||||
<p>What colors shall we use?</p>
|
||||
<label for="primaryColor">Primary</label>
|
||||
<div id="primary" class="colorPicker">
|
||||
<a class="color"><div class="colorInner"></div></a>
|
||||
<div class="track"></div>
|
||||
<ul class="dropdown"><li></li></ul>
|
||||
<input type="hidden" class="colorInput" value='#1ABC9C' name='primaryColor' id='primaryColor' autocomplete="off"/>
|
||||
</div>
|
||||
<label for="secondaryColor">Secondary</label>
|
||||
<div id="secondary" class="colorPicker">
|
||||
<a class="color"><div class="colorInner"></div></a>
|
||||
<div class="track"></div>
|
||||
<ul class="dropdown"><li></li></ul>
|
||||
<input type="hidden" class="colorInput" value='#ffff' name='secondaryColor' id='secondaryColor' autocomplete="off"/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row" style="margin-top: 30px; text-align: center;">
|
||||
<p id="advancedOptionsLabel"><span id="showMoreOptions">Show</span><span id="hideMoreOptions">Hide</span> more options....</p>
|
||||
<div id="advancedOptions">
|
||||
<label for="seed" class="tooltip" title="using seeds allows you to reproduce cards">Seed</label><br>
|
||||
<input type="text" id="seed" name="seed" placeholder="Seed" maxlength="10" autocomplete="off">
|
||||
<label for="space-size">Spacebar size</label>
|
||||
<input type="number" min="1" max="8" style="width: 15em;" name="space-length" id="space-size" placeholder="Spacebar size (Default: 8)" maxlength="10" autocomplete="off">
|
||||
</div>
|
||||
</div>
|
||||
<input type="hidden" value='{{sessiontoken}}'/>
|
||||
|
||||
<div class="row" style="margin-top: 30px; text-align: center;">
|
||||
<input type="submit" value="Generate PDF!"/><br>
|
||||
</div>
|
||||
</form>
|
||||
<p>Wanna buy a card? Checkout <a href="https://www.qwertycards.com" target="_blank">qwertycards.com</a>!</p>
|
||||
<p>Fork me on <a href="https://github.com/raphiz/passwordcards" target="_blank">Github</a>!</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript" src="resources/js/jquery-2.1.3.js"></script>
|
||||
<script type="text/javascript" src="resources/js/jquery.tinycolorpicker.js"></script>
|
||||
<script type="text/javascript" src="resources/js/index.js"></script>
|
||||
|
||||
<!-- End Document
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
</body>
|
||||
</html>
|
22
resources/js/index.js
Normal file
22
resources/js/index.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
(function($) {
|
||||
|
||||
$('#advancedOptionsLabel').click(function() {
|
||||
|
||||
$('#showMoreOptions').toggle();
|
||||
$('#hideMoreOptions').toggle();
|
||||
$('#advancedOptions').slideToggle();
|
||||
});
|
||||
|
||||
$('#with-other').click(function() {
|
||||
$('#other-chars').parent().slideToggle();
|
||||
});
|
||||
$("#primary").tinycolorpicker();
|
||||
var picker = $('#primary').data("plugin_tinycolorpicker");
|
||||
picker.setColor("#1ABC9C");
|
||||
|
||||
$("#secondary").tinycolorpicker();
|
||||
var picker = $('#secondary').data("plugin_tinycolorpicker");
|
||||
picker.setColor("#ffffff");
|
||||
|
||||
|
||||
})(jQuery);
|
9205
resources/js/jquery-2.1.3.js
vendored
Normal file
9205
resources/js/jquery-2.1.3.js
vendored
Normal file
File diff suppressed because it is too large
Load diff
303
resources/js/jquery.tinycolorpicker.js
Normal file
303
resources/js/jquery.tinycolorpicker.js
Normal file
|
@ -0,0 +1,303 @@
|
|||
;(function(factory) {
|
||||
if(typeof define === 'function' && define.amd) {
|
||||
define(['jquery'], factory);
|
||||
}
|
||||
else if(typeof exports === 'object') {
|
||||
module.exports = factory(require("jquery"));
|
||||
}
|
||||
else {
|
||||
factory(jQuery);
|
||||
}
|
||||
}
|
||||
(function($) {
|
||||
var pluginName = "tinycolorpicker"
|
||||
, defaults = {
|
||||
colors : ["#ffffff", "#A7194B","#FE2712","#FB9902","#FABC02","#FEFE33","#D0EA2B","#66B032","#0391CE","#0247FE","#3D01A5","#8601AF"]
|
||||
, backgroundUrl : null
|
||||
}
|
||||
;
|
||||
|
||||
function Plugin($container, options) {
|
||||
/**
|
||||
* The options of the colorpicker extended with the defaults.
|
||||
*
|
||||
* @property options
|
||||
* @type Object
|
||||
*/
|
||||
this.options = $.extend({}, defaults, options);
|
||||
|
||||
/**
|
||||
* @property _defaults
|
||||
* @type Object
|
||||
* @private
|
||||
* @default defaults
|
||||
*/
|
||||
this._defaults = defaults;
|
||||
|
||||
/**
|
||||
* @property _name
|
||||
* @type String
|
||||
* @private
|
||||
* @final
|
||||
* @default 'tinycolorpicker'
|
||||
*/
|
||||
this._name = pluginName;
|
||||
|
||||
var self = this
|
||||
, $track = $container.find(".track")
|
||||
, $color = $container.find(".color")
|
||||
, $canvas = null
|
||||
, $colorInput = $container.find(".colorInput")
|
||||
, $dropdown = $container.find(".dropdown")
|
||||
, $dropdownItem = $dropdown.find("li").remove()
|
||||
|
||||
, context = null
|
||||
, mouseIsDown = false
|
||||
, hasCanvas = !!document.createElement("canvas").getContext
|
||||
, touchEvents = "ontouchstart" in document.documentElement
|
||||
;
|
||||
|
||||
/**
|
||||
* The current active color in hex.
|
||||
*
|
||||
* @property colorHex
|
||||
* @type String
|
||||
* @default ""
|
||||
*/
|
||||
this.colorHex = "";
|
||||
|
||||
/**
|
||||
* The current active color in rgb.
|
||||
*
|
||||
* @property colorRGB
|
||||
* @type String
|
||||
* @default ""
|
||||
*/
|
||||
this.colorRGB = "";
|
||||
|
||||
/**
|
||||
* @method _initialize
|
||||
* @private
|
||||
*/
|
||||
function _initialize() {
|
||||
if(hasCanvas) {
|
||||
$canvas = $("<canvas></canvas>");
|
||||
$track.append($canvas);
|
||||
|
||||
context = $canvas[0].getContext( "2d" );
|
||||
|
||||
_setImage();
|
||||
}
|
||||
else {
|
||||
$.each(self.options.colors, function(index, color) {
|
||||
var $clone = $dropdownItem.clone();
|
||||
|
||||
$clone.css("backgroundColor", color);
|
||||
$clone.attr("data-color", color);
|
||||
|
||||
$dropdown.append($clone);
|
||||
});
|
||||
}
|
||||
|
||||
_setEvents();
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
/**
|
||||
* @method _setImage
|
||||
* @private
|
||||
*/
|
||||
function _setImage() {
|
||||
var colorPicker = new Image()
|
||||
, backgroundUrl = $track.css("background-image").replace(/"/g, "").replace(/url\(|\)$/ig, "")
|
||||
;
|
||||
|
||||
$track.css("background-image", "none");
|
||||
|
||||
$(colorPicker).load(function() {
|
||||
$canvas.attr("width", this.width);
|
||||
$canvas.attr("height", this.height);
|
||||
|
||||
context.drawImage(colorPicker, 0, 0, this.width, this.height);
|
||||
});
|
||||
|
||||
colorPicker.src = self.options.backgroundUrl || backgroundUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* @method _setEvents
|
||||
* @private
|
||||
*/
|
||||
function _setEvents() {
|
||||
var eventType = touchEvents ? "touchstart" : "mousedown";
|
||||
|
||||
if(hasCanvas) {
|
||||
$color.bind(eventType, function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
$track.toggle();
|
||||
|
||||
$(document).bind("mousedown.colorpicker", function(event) {
|
||||
$(document).unbind(".colorpicker");
|
||||
|
||||
$track.hide();
|
||||
});
|
||||
});
|
||||
|
||||
if(!touchEvents) {
|
||||
$canvas.mousedown(function(event) {
|
||||
mouseIsDown = true;
|
||||
|
||||
_getColorCanvas(event);
|
||||
|
||||
$(document).bind("mouseup.colorpicker", function(event) {
|
||||
mouseIsDown = false;
|
||||
|
||||
$(document).unbind(".colorpicker");
|
||||
|
||||
$track.hide();
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$canvas.mousemove(_getColorCanvas);
|
||||
}
|
||||
else {
|
||||
$canvas.bind("touchstart", function(event) {
|
||||
mouseIsDown = true;
|
||||
|
||||
_getColorCanvas(event.originalEvent.touches[0]);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$canvas.bind("touchmove", function(event) {
|
||||
_getColorCanvas(event.originalEvent.touches[0]);
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
$canvas.bind("touchend", function(event) {
|
||||
mouseIsDown = false;
|
||||
|
||||
$track.hide();
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
else {
|
||||
$color.bind("mousedown", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
$dropdown.toggle();
|
||||
});
|
||||
|
||||
$dropdown.delegate("li", "mousedown", function(event) {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
var color = $(this).attr("data-color");
|
||||
|
||||
self.setColor(color);
|
||||
|
||||
$dropdown.hide();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @method _getColorCanvas
|
||||
* @private
|
||||
*/
|
||||
function _getColorCanvas(event) {
|
||||
if(mouseIsDown) {
|
||||
var $target = $(event.target)
|
||||
, offset = $target.offset()
|
||||
, colorData = context.getImageData(event.pageX - offset.left, event.pageY - offset.top, 1, 1).data
|
||||
;
|
||||
|
||||
self.setColor("rgb(" + colorData[0] + "," + colorData[1] + "," + colorData[2] + ")");
|
||||
|
||||
/**
|
||||
* The change event will trigger when a new color is set.
|
||||
*
|
||||
* @event change
|
||||
*/
|
||||
$container.trigger("change", [self.colorHex, self.colorRGB]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the color to a given hex or rgb color.
|
||||
*
|
||||
* @method setColor
|
||||
* @chainable
|
||||
*/
|
||||
this.setColor = function(color) {
|
||||
if(color.indexOf("#") >= 0) {
|
||||
self.colorHex = color;
|
||||
self.colorRGB = self.hexToRgb(self.colorHex);
|
||||
}
|
||||
else {
|
||||
self.colorRGB = color;
|
||||
self.colorHex = self.rgbToHex(self.colorRGB);
|
||||
}
|
||||
|
||||
$color.find(".colorInner").css("backgroundColor", self.colorHex);
|
||||
$colorInput.val(self.colorHex);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert hex to rgb
|
||||
*
|
||||
* @method hexToRgb
|
||||
* @chainable
|
||||
*/
|
||||
this.hexToRgb = function(hex) {
|
||||
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
||||
|
||||
return "rgb(" + parseInt(result[1], 16) + "," + parseInt(result[2], 16) + "," + parseInt(result[3], 16) + ")";
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert rgb to hex
|
||||
*
|
||||
* @method rgbToHex
|
||||
* @chainable
|
||||
*/
|
||||
this.rgbToHex = function(rgb) {
|
||||
var result = rgb.match(/\d+/g);
|
||||
|
||||
function hex(x) {
|
||||
var digits = new Array("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F");
|
||||
return isNaN(x) ? "00" : digits[(x - x % 16 ) / 16] + digits[x % 16];
|
||||
}
|
||||
|
||||
return "#" + hex(result[0]) + hex(result[1]) + hex(result[2]);
|
||||
};
|
||||
|
||||
return _initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* @class tinycolorpicker
|
||||
* @constructor
|
||||
* @param {Object} options
|
||||
@param {Array} [options.colors=[]] fallback colors for old browsers (ie8-).
|
||||
@param {String} [options.backgroundUrl=''] It will look for a css image on the track div. If not found it will look if there's a url in this property.
|
||||
*/
|
||||
$.fn[pluginName] = function(options) {
|
||||
return this.each(function() {
|
||||
if(!$.data(this, "plugin_" + pluginName)) {
|
||||
$.data(this, "plugin_" + pluginName, new Plugin($(this), options));
|
||||
}
|
||||
});
|
||||
};
|
||||
}));
|
BIN
resources/text-color.png
Normal file
BIN
resources/text-color.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
90
src/CardCreator.php
Normal file
90
src/CardCreator.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace raphiz\passwordcards;
|
||||
|
||||
class CardCreator
|
||||
{
|
||||
private $configration = null;
|
||||
|
||||
public function __construct($configration)
|
||||
{
|
||||
if ($configration == null) {
|
||||
throw new \Exception('The given $configuration is null!');
|
||||
}
|
||||
|
||||
if ($configration instanceof Configuration == false) {
|
||||
throw new \Exception(
|
||||
'The given $configuration is not a valid ' .
|
||||
'Configuration object.'
|
||||
);
|
||||
}
|
||||
|
||||
$this->configration = $configration;
|
||||
}
|
||||
|
||||
public function getSvgFilePath($template_name)
|
||||
{
|
||||
return __DIR__ . "/../templates/$template_name.svg";
|
||||
}
|
||||
|
||||
public function getSvgTemplate($template_name)
|
||||
{
|
||||
return file_get_contents($this->getSvgFilePath($template_name));
|
||||
}
|
||||
|
||||
public function render($svg)
|
||||
{
|
||||
// Get and count available characters
|
||||
$chars = $this->configration->getPatternCharacters();
|
||||
$char_count = count($chars);
|
||||
|
||||
// set seed
|
||||
$seed = $this->configration->seed;
|
||||
mt_srand($seed);
|
||||
|
||||
for ($i = 0; $i < strlen($this->configration->keys); $i++) {
|
||||
$prefix = '$' . ($i+1);
|
||||
$equivalent = $chars[mt_rand(0, $char_count-1)];
|
||||
|
||||
$equivalent = $this->escape($equivalent);
|
||||
|
||||
// Replace the equivalent on the "keyboard"
|
||||
$svg = str_replace('$' . ($i+1) . '$', $equivalent, $svg);
|
||||
|
||||
$svg = str_replace('$k' . ($i+1) . '$', $this->configration->keys[$i], $svg);
|
||||
|
||||
}
|
||||
|
||||
$space_lenght = $this->configration->spaceBarSize;
|
||||
$space = '';
|
||||
for ($i = 0; $i < $space_lenght; $i++) {
|
||||
$space .= $this->escape($chars[mt_rand(0, $char_count-1)]);
|
||||
}
|
||||
|
||||
$svg = str_replace('$SPACE$', $space, $svg);
|
||||
|
||||
$svg = str_replace('$SEED$', $seed, $svg);
|
||||
|
||||
$svg = str_replace('$PRIMARY$', $this->configration->primaryColor, $svg);
|
||||
|
||||
$svg = str_replace('$SECONDARY$', $this->configration->secondaryColor, $svg);
|
||||
|
||||
$svg = str_replace('$TEXT$', $this->escape($this->configration->text), $svg);
|
||||
|
||||
$svg = str_replace('$PATTERN$', $this->escape($this->configration->pattern), $svg);
|
||||
|
||||
return $svg;
|
||||
}
|
||||
private function escape($str)
|
||||
{
|
||||
return htmlentities(utf8_encode($str), ENT_XML1);
|
||||
}
|
||||
|
||||
|
||||
public function renderIntoTempfile($svg)
|
||||
{
|
||||
$uri = tempnam("/tmp", "php");
|
||||
file_put_contents($uri, $this->render($svg));
|
||||
return $uri;
|
||||
}
|
||||
}
|
90
src/Configuration.php
Normal file
90
src/Configuration.php
Normal file
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace raphiz\passwordcards;
|
||||
|
||||
class Configuration
|
||||
{
|
||||
|
||||
const DEFAULT_PATTERN = 'a-zA-Z0-9~*-*';
|
||||
|
||||
const LOWER = "abcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
const UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
|
||||
const NUMBERS = "0123456789";
|
||||
|
||||
const SYMBOLS = '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~';
|
||||
|
||||
public $seed = null;
|
||||
|
||||
public $pattern = null;
|
||||
|
||||
public $primaryColor = null;
|
||||
|
||||
public $secondaryColor = null;
|
||||
|
||||
public $text = null;
|
||||
|
||||
public $keys = null;
|
||||
|
||||
public function __construct($seed, $pattern, $keys, $spaceBarSize, $text, $primaryColor, $secondaryColor)
|
||||
{
|
||||
$this->seed = self::evalSeed($seed);
|
||||
$this->pattern = self::evalPattern($pattern);
|
||||
$this->keys = self::evalKeys($keys);
|
||||
$this->primaryColor = $primaryColor;
|
||||
$this->text = $text;
|
||||
$this->spaceBarSize = $spaceBarSize;
|
||||
$this->secondaryColor = $secondaryColor;
|
||||
}
|
||||
|
||||
public function getPatternCharacters()
|
||||
{
|
||||
return str_split(self::completePattern($this->pattern));
|
||||
}
|
||||
|
||||
public static function completePattern($pattern)
|
||||
{
|
||||
$pattern = str_replace('a-z', self::LOWER, $pattern);
|
||||
$pattern = str_replace('A-Z', self::UPPER, $pattern);
|
||||
$pattern = str_replace('0-9', self::NUMBERS, $pattern);
|
||||
$pattern = str_replace('*-*', self::SYMBOLS, $pattern);
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* If no (numeric) seed is provided, generate one.
|
||||
*/
|
||||
public static function evalSeed($seed)
|
||||
{
|
||||
if ($seed == null || !is_numeric($seed)) {
|
||||
list($usec, $sec) = explode(' ', microtime());
|
||||
$seed = (float) $sec + ((float) $usec * 100000);
|
||||
}
|
||||
return $seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* If no pattern is provided, return the default.
|
||||
*/
|
||||
public static function evalPattern($pattern)
|
||||
{
|
||||
if ($pattern == null) {
|
||||
$pattern = self::DEFAULT_PATTERN;
|
||||
}
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* If no keys are provided, use qwerty.
|
||||
*/
|
||||
public static function evalKeys($keys)
|
||||
{
|
||||
// Return qwertz
|
||||
if (strtolower($keys) === 'qwertz') {
|
||||
return 'QWERTZUIOPASDFGHJKLYXCVBNM';
|
||||
}
|
||||
// Return qwerty
|
||||
return 'QWERTYUIOPASDFGHJKLZXCVBNM';
|
||||
}
|
||||
}
|
49
src/PDFRenderer.php
Normal file
49
src/PDFRenderer.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace raphiz\passwordcards;
|
||||
|
||||
class PDFRenderer
|
||||
{
|
||||
public static function render($front, $back)
|
||||
{
|
||||
// create new PDF document
|
||||
$pdf = new \TCPDF(PDF_PAGE_ORIENTATION, 'mm', 'A4', true, 'UTF-8', false);
|
||||
|
||||
// set document information
|
||||
$pdf->SetAuthor('Raphael Zimmermann');
|
||||
$pdf->SetTitle('Password Card');
|
||||
$pdf->SetSubject('Password Card');
|
||||
|
||||
$pdf->SetPrintHeader(false);
|
||||
$pdf->SetPrintFooter(false);
|
||||
|
||||
// add a page
|
||||
$pdf->AddPage();
|
||||
|
||||
// Mark the position to fold...
|
||||
$pdf->Line(95, 10, 95, 13);
|
||||
$pdf->Line(95, 72, 95, 75);
|
||||
|
||||
// Add the front svg
|
||||
$pdf->ImageSVG(
|
||||
$file = $front,
|
||||
$x = 10,
|
||||
$y = 15,
|
||||
$w = '85',
|
||||
$h = '55'
|
||||
);
|
||||
|
||||
// Add the back svg
|
||||
$pdf->ImageSVG(
|
||||
$file = $back,
|
||||
$x = 95,
|
||||
$y = 15,
|
||||
$w = '85',
|
||||
$h = '55'
|
||||
);
|
||||
|
||||
|
||||
//Close and output PDF document
|
||||
return $pdf->Output('generated.pdf', 'S');
|
||||
}
|
||||
}
|
136
src/RequestUtils.php
Normal file
136
src/RequestUtils.php
Normal file
|
@ -0,0 +1,136 @@
|
|||
<?php
|
||||
namespace raphiz\passwordcards;
|
||||
|
||||
class RequestUtils
|
||||
{
|
||||
public static function isPost()
|
||||
{
|
||||
return $_SERVER['REQUEST_METHOD'] == "POST";
|
||||
}
|
||||
|
||||
public static function parseSeed()
|
||||
{
|
||||
if (
|
||||
isset($_POST['seed']) &&
|
||||
is_numeric($_POST['seed'])
|
||||
) {
|
||||
return $_POST['seed'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static function parseSpacebarSize()
|
||||
{
|
||||
if (
|
||||
isset($_POST['space-length']) &&
|
||||
is_numeric($_POST['space-length']) &&
|
||||
$_POST['space-length'] < 8 &&
|
||||
$_POST['space-length'] > 0
|
||||
) {
|
||||
return $_POST['space-length'];
|
||||
}
|
||||
return 8;
|
||||
}
|
||||
|
||||
public static function parseText()
|
||||
{
|
||||
if (isset($_POST['msg'])) {
|
||||
return substr($_POST['msg'], 0, 20);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function parsePrimaryColor()
|
||||
{
|
||||
if (
|
||||
isset($_POST['primaryColor']) &&
|
||||
preg_match("/#[0-9a-zA-Z]{6}/", $_POST['primaryColor'])
|
||||
) {
|
||||
return $_POST['primaryColor'];
|
||||
}
|
||||
return '#1ABC9C';
|
||||
}
|
||||
|
||||
public static function parseSecondaryColor()
|
||||
{
|
||||
if (
|
||||
isset($_POST['secondaryColor']) &&
|
||||
preg_match("/#[0-9a-zA-Z]{6}/", $_POST['secondaryColor'])
|
||||
) {
|
||||
return $_POST['secondaryColor'];
|
||||
}
|
||||
return '#ffffff';
|
||||
}
|
||||
|
||||
public static function parseKeyboardLayout()
|
||||
{
|
||||
if (
|
||||
isset($_POST['keyboardlayout']) &&
|
||||
preg_match("/qwerty|qwertz/", $_POST['keyboardlayout'])
|
||||
) {
|
||||
return strtolower($_POST['keyboardlayout']);
|
||||
}
|
||||
return 'qwerty';
|
||||
}
|
||||
public static function parsePattern()
|
||||
{
|
||||
$pattern = "";
|
||||
|
||||
// With numbers?
|
||||
if (self::isChecked('with-numbers')) {
|
||||
$pattern .= '0-9';
|
||||
}
|
||||
|
||||
// With lower?
|
||||
if (self::isChecked('with-lower')) {
|
||||
$pattern .= 'a-z';
|
||||
}
|
||||
|
||||
// With upper?
|
||||
if (self::isChecked('with-upper')) {
|
||||
$pattern .= 'A-Z';
|
||||
}
|
||||
|
||||
// With symbols?
|
||||
if (self::isChecked('with-symbols')) {
|
||||
$pattern .= '*-*';
|
||||
}
|
||||
|
||||
// With space?
|
||||
if (self::isChecked('with-space')) {
|
||||
$pattern .= ' ';
|
||||
}
|
||||
|
||||
// With others?
|
||||
if (self::isChecked('with-other')) {
|
||||
if (isset($_POST['other-chars'])) {
|
||||
$pattern .= substr($_POST['other-chars'], 0, 20);
|
||||
}
|
||||
}
|
||||
return $pattern;
|
||||
}
|
||||
|
||||
private static function isChecked($parameter)
|
||||
{
|
||||
if (
|
||||
isset($_POST[$parameter]) &&
|
||||
$_POST[$parameter] === "on"
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function preparePdfHeader($length)
|
||||
{
|
||||
header('Content-Description: File Transfer');
|
||||
header('Content-Type: application/pdf');
|
||||
header('Content-Disposition: attachment; filename=passwordcard.pdf');
|
||||
header('Content-Transfer-Encoding: binary');
|
||||
header('Content-Length: ' . $length);
|
||||
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
|
||||
header('Expires: 0');
|
||||
header('Pragma: public');
|
||||
}
|
||||
|
||||
}
|
119
templates/simple_back.svg
Normal file
119
templates/simple_back.svg
Normal file
|
@ -0,0 +1,119 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="301.18109"
|
||||
height="194.88188"
|
||||
id="svg3889"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="simple_back_en.svg">
|
||||
<defs
|
||||
id="defs3891" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="$PRIMARY$"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="1"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="1.979899"
|
||||
inkscape:cx="69.231099"
|
||||
inkscape:cy="112.82896"
|
||||
inkscape:document-units="mm"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
units="mm"
|
||||
inkscape:window-width="1600"
|
||||
inkscape:window-height="839"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="28"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid3817"
|
||||
empspacing="5"
|
||||
visible="true"
|
||||
enabled="true"
|
||||
snapvisiblegridlinesonly="true" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata3894">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-857.4803)">
|
||||
<rect
|
||||
style="fill:$PRIMARY$;fill-opacity:1;stroke:none"
|
||||
id="rect3204"
|
||||
x="0"
|
||||
y="857.48029"
|
||||
height="194.8819"
|
||||
width="301.18109" />
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:$SECONDARY$;fill-opacity:1;stroke:none;font-family:Open Sans;-inkscape-font-specification:Open Sans"
|
||||
x="9.9902725"
|
||||
y="1041.1512"
|
||||
id="text3210"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3212"
|
||||
x="9.9902725"
|
||||
y="1041.1512"
|
||||
style="font-size:10px;text-align:start;text-anchor:start;fill:$SECONDARY$;fill-opacity:1">/$SEED$/$PATTERN$/</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3207"
|
||||
y="1029.4025"
|
||||
x="242.0994"
|
||||
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:$SECONDARY$;fill-opacity:1;stroke:none;font-family:Open Sans;-inkscape-font-specification:Open Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="text-align:center;text-anchor:middle;fill:$SECONDARY$;fill-opacity:1"
|
||||
y="1029.4025"
|
||||
x="242.0994"
|
||||
id="tspan3209"
|
||||
sodipodi:role="line" /></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3766"
|
||||
y="1039.33"
|
||||
x="236.00528"
|
||||
style="font-size:20px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:$SECONDARY$;fill-opacity:1;stroke:none;font-family:Open Sans;-inkscape-font-specification:Open Sans"
|
||||
xml:space="preserve"><tspan
|
||||
style="font-size:10px;text-align:center;text-anchor:middle;fill:$SECONDARY$;fill-opacity:1"
|
||||
y="1039.33"
|
||||
x="236.00528"
|
||||
id="tspan3768"
|
||||
sodipodi:role="line">http://raphael.li/pwcard</tspan></text>
|
||||
<text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3808"
|
||||
y="947.46991"
|
||||
x="150.53195"
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:20px;line-height:125%;font-family:'Open Sans';-inkscape-font-specification:'Open Sans';letter-spacing:0px;word-spacing:0px;fill:$PRIMARY$;fill-opacity:1;stroke:none"
|
||||
xml:space="preserve"><tspan
|
||||
id="tspan3812"
|
||||
style="font-weight:bold;-inkscape-font-specification:'Open Sans Bold';text-align:center;text-anchor:middle;fill:$SECONDARY$;fill-opacity:1"
|
||||
y="947.46991"
|
||||
x="150.53195"
|
||||
sodipodi:role="line">$TEXT$</tspan></text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.4 KiB |
1349
templates/simple_front.svg
Normal file
1349
templates/simple_front.svg
Normal file
File diff suppressed because it is too large
Load diff
After Width: | Height: | Size: 58 KiB |
43
tests/CardCreatorTest.php
Normal file
43
tests/CardCreatorTest.php
Normal file
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
namespace raphiz\passwordcards;
|
||||
|
||||
class CardCreatorTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage The given $configuration is null!
|
||||
*/
|
||||
public function testConstructorDeclinesNull()
|
||||
{
|
||||
new CardCreator(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Exception
|
||||
* @expectedExceptionMessage The given $configuration is not a valid Configuration object.
|
||||
*/
|
||||
public function testConstructorDeclinesNonConfigurationInstances()
|
||||
{
|
||||
new CardCreator('fooBaa');
|
||||
}
|
||||
|
||||
public function testGetSvgFilePath()
|
||||
{
|
||||
$creator = new CardCreator($this->testConfiguration);
|
||||
$file = $creator->getSvgFilePath('abc');
|
||||
$this->assertStringEndsWith('/templates/abc.svg', $file);
|
||||
}
|
||||
|
||||
public function testCreateHappyPath()
|
||||
{
|
||||
$creator = new CardCreator($this->testConfiguration);
|
||||
$creator->render($creator->getSvgFilePath('simple_front'));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->testConfiguration = new Configuration(10, null, null, 8, '', '#000000', '#ffffff');
|
||||
}
|
||||
}
|
75
tests/ConfigurationTest.php
Normal file
75
tests/ConfigurationTest.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
namespace raphiz\passwordcards;
|
||||
|
||||
class ConfigurationTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
public function testEvalSeedReturnsGivenNonNullSeed()
|
||||
{
|
||||
// Verify that if a seed is given, it's returned properly
|
||||
$this->assertEquals(1, Configuration::evalSeed(1));
|
||||
$this->assertEquals(99, Configuration::evalSeed(99));
|
||||
}
|
||||
|
||||
public function testEvalSeedGeneratesSeedIfNullGiven()
|
||||
{
|
||||
$seed1 = Configuration::evalSeed(null);
|
||||
$seed2 = Configuration::evalSeed(null);
|
||||
|
||||
// Not null?
|
||||
$this->assertNotNull($seed1);
|
||||
$this->assertNotNull($seed2);
|
||||
|
||||
// Is float?
|
||||
$this->assertInternalType('float', $seed1);
|
||||
$this->assertInternalType('float', $seed2);
|
||||
|
||||
// The seeds shall not be equal!
|
||||
$this->assertFalse($seed1 == $seed2);
|
||||
}
|
||||
|
||||
public function testEvalPatternReturnsGivenNonNullPattern()
|
||||
{
|
||||
$this->assertEquals('a-zA-Z', Configuration::evalPattern('a-zA-Z'));
|
||||
$this->assertEquals('a-z', Configuration::evalPattern('a-z'));
|
||||
}
|
||||
|
||||
public function testEvalPatternReturnsDefaultIfNull()
|
||||
{
|
||||
$this->assertEquals('a-zA-Z0-9~*-*', Configuration::evalPattern(null));
|
||||
}
|
||||
|
||||
public function testCompletePatterAcceptsShortForms()
|
||||
{
|
||||
$this->assertEquals(
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
Configuration::completePattern('A-Z')
|
||||
);
|
||||
$this->assertEquals(
|
||||
'0123456789',
|
||||
Configuration::completePattern('0-9')
|
||||
);
|
||||
$this->assertEquals(
|
||||
'!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~',
|
||||
Configuration::completePattern('*-*')
|
||||
);
|
||||
|
||||
# Combination
|
||||
$this->assertEquals(
|
||||
'abcdefghijklmnopqrstuvwxyz0123456789',
|
||||
Configuration::completePattern('a-z0-9')
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
public function testGetPatternCharactersHappyPath()
|
||||
{
|
||||
//$seed, $pattern, $keys, $spaceBarSize, $text, $primaryColor, $secondaryColor
|
||||
$cfg = new Configuration(null, 'a0-', null, 8, '', '#000000', '#ffffff');
|
||||
$chars = $cfg->getPatternCharacters();
|
||||
$this->assertEquals('a', $chars[0]);
|
||||
$this->assertEquals('0', $chars[1]);
|
||||
$this->assertEquals('-', $chars[2]);
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue