Move frontend to Vue
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
e4097a42af
commit
a2c7b10418
12 changed files with 7702 additions and 792 deletions
8
Makefile
8
Makefile
|
@ -5,18 +5,16 @@ VER_GIBBERISH_AES=1.0.0
|
|||
VER_JQUERY=3.4.1
|
||||
VER_POPPER=1.15.0
|
||||
VER_VUE=2.6.10
|
||||
VER_VUE_I18N=8.11.2
|
||||
|
||||
|
||||
default: generate
|
||||
|
||||
generate: l10n download_libs
|
||||
generate: download_libs
|
||||
docker run --rm -ti -v $(CURDIR):$(CURDIR) -w $(CURDIR)/src node:10-alpine \
|
||||
sh -exc "npm ci && npm run build && rm -rf node_modules && chown -R $(shell id -u) ../frontend"
|
||||
go generate
|
||||
|
||||
l10n:
|
||||
cd frontend/locale && goi18n *
|
||||
|
||||
publish:
|
||||
curl -sSLo golang.sh https://raw.githubusercontent.com/Luzifer/github-publish/master/golang.sh
|
||||
bash golang.sh
|
||||
|
@ -38,4 +36,4 @@ libs_css:
|
|||
|
||||
libs_js:
|
||||
mkdir -p frontend/js
|
||||
curl -sSfLo frontend/js/bundle.js "https://cdn.jsdelivr.net/combine/npm/jquery@$(VER_JQUERY),npm/popper.js@$(VER_POPPER),npm/bootstrap@$(VER_BOOTSTRAP)/dist/js/bootstrap.min.js,npm/gibberish-aes@$(VER_GIBBERISH_AES)/dist/gibberish-aes-$(VER_GIBBERISH_AES).min.js,npm/vue@$(VER_VUE)"
|
||||
curl -sSfLo frontend/js/bundle.js "https://cdn.jsdelivr.net/combine/npm/jquery@$(VER_JQUERY),npm/popper.js@$(VER_POPPER),npm/bootstrap@$(VER_BOOTSTRAP)/dist/js/bootstrap.min.js,npm/gibberish-aes@$(VER_GIBBERISH_AES)/dist/gibberish-aes-$(VER_GIBBERISH_AES).min.js,npm/vue@$(VER_VUE),npm/vue-i18n@$(VER_VUE_I18N)/dist/vue-i18n.min.js"
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -6,124 +6,15 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<link rel="stylesheet" href="/css/bundle.css" integrity="{{SRIHash `/css/bundle.css`}}" />
|
||||
<link rel="stylesheet" href="/css/all.min.css" integrity="{{SRIHash `/css/all.min.css`}}" />
|
||||
<link rel="stylesheet" href="css/all.min.css"/>
|
||||
|
||||
<title>OTS - One Time Secrets</title>
|
||||
|
||||
<style>
|
||||
#somethingwrong, #notfound, #cardReadSecret, #cardSecretURL, #cardReadSecretPre { display: none; }
|
||||
.footer { color: #2f2f2f; font-size: 0.9em; text-align: center; }
|
||||
textarea { font-family: monospace; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
|
||||
<a class="navbar-brand" href="#"><i class="fas fa-user-secret"></i> OTS - One Time Secrets</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav ml-auto">
|
||||
<li class="nav-item"></li>
|
||||
<li class="nav-item"><a href="#" id="newSecret"><i class="fas fa-plus"></i> {{T "btn-new-secret"}}</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container mt-4">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-8">
|
||||
<div class="alert alert-danger" role="alert" id="notfound">
|
||||
<i class="fas fa-question-circle" aria-hidden="true"></i>
|
||||
{{T "alert-secret-not-found"}}
|
||||
</div>
|
||||
<div class="alert alert-danger" role="alert" id="somethingwrong">
|
||||
<i class="fas fa-question-circle" aria-hidden="true"></i>
|
||||
{{T "alert-something-went-wrong"}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
|
||||
<div class="card border-primary" id="cardNewSecret">
|
||||
<div class="card-header bg-primary text-white">
|
||||
{{T "title-new-secret"}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="formCreateSecret">
|
||||
<div class="form-group">
|
||||
<label for="secret">{{T "label-secret-data"}}</label>
|
||||
<textarea class="form-control" rows="5" id="secret"></textarea>
|
||||
</div>
|
||||
<input class="btn btn-success" type="submit" value="{{T "btn-create-secret"}}">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card border-success" id="cardSecretURL">
|
||||
<div class="card-header bg-success text-white">
|
||||
{{T "title-secret-created"}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>
|
||||
{{T "text-pre-url"}}
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" readonly>
|
||||
</div>
|
||||
<p>
|
||||
{{T "text-burn-hint"}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card border-primary" id="cardReadSecretPre">
|
||||
<div class="card-header bg-primary text-white">
|
||||
{{T "title-reading-secret"}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p>
|
||||
{{T "text-pre-reveal-hint"}}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button class="btn btn-success" id="revealSecret">{{T "btn-reveal-secret"}}</button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card border-primary" id="cardReadSecret">
|
||||
<div class="card-header bg-primary text-white">
|
||||
{{T "title-reading-secret"}}
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="form-group">
|
||||
<textarea class="form-control" rows="5" readonly></textarea>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
{{T "text-hint-burned"}}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> <!-- /.col-md-12 -->
|
||||
</div> <!-- /.row -->
|
||||
|
||||
<div class="row mt-5">
|
||||
<div class="col-md-12 footer">
|
||||
{{T "text-powered-by"}} <a href="https://github.com/Luzifer/ots"><i class="fab fa-github"></i> Luzifer/OTS</a> {{.version}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/js/bundle.js" integrity="{{SRIHash `/js/bundle.js`}}"></script>
|
||||
<script src="app.js" integrity="{{SRIHash `app.js`}}"></script>
|
||||
<script src="vars.js"></script>
|
||||
<script src="app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
45
main.go
45
main.go
|
@ -9,7 +9,6 @@ import (
|
|||
"os"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
log "github.com/sirupsen/logrus"
|
||||
|
@ -56,6 +55,7 @@ func main() {
|
|||
|
||||
r := mux.NewRouter()
|
||||
api.Register(r.PathPrefix("/api").Subrouter())
|
||||
r.HandleFunc("/vars.js", handleVars)
|
||||
r.PathPrefix("/").HandlerFunc(http_helpers.GzipFunc(assetDelivery))
|
||||
|
||||
log.Fatalf("HTTP server quit: %s", http.ListenAndServe(cfg.Listen, http_helpers.NewHTTPLogHandler(r)))
|
||||
|
@ -67,6 +67,12 @@ func assetDelivery(res http.ResponseWriter, r *http.Request) {
|
|||
assetName = "/index.html"
|
||||
}
|
||||
|
||||
if strings.LastIndex(assetName, ".") < 0 {
|
||||
// There are no assets with no dot in it
|
||||
http.Error(res, "404 not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
ext := assetName[strings.LastIndex(assetName, "."):]
|
||||
assetData, err := Asset(path.Join("frontend", assetName))
|
||||
if err != nil {
|
||||
|
@ -75,21 +81,38 @@ func assetDelivery(res http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
res.Header().Set("Content-Type", mime.TypeByExtension(ext))
|
||||
|
||||
if assetName != "/index.html" {
|
||||
// Do not use template engine on other files than index.html
|
||||
res.Write(assetData)
|
||||
return
|
||||
}
|
||||
|
||||
tpl, err := template.New(assetName).Funcs(addTranslateFunc(tplFuncs, r)).Parse(string(assetData))
|
||||
func handleVars(w http.ResponseWriter, r *http.Request) {
|
||||
cookie, _ := r.Cookie("lang")
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("Template for asset %q has an error: %s", assetName, err)
|
||||
return
|
||||
cookieLang := ""
|
||||
if cookie != nil {
|
||||
cookieLang = cookie.Value
|
||||
}
|
||||
acceptLang := r.Header.Get("Accept-Language")
|
||||
defaultLang := "en" // known valid language
|
||||
|
||||
tpl.Execute(res, map[string]interface{}{
|
||||
vars := map[string]string{
|
||||
"version": version,
|
||||
})
|
||||
}
|
||||
|
||||
switch {
|
||||
case cookieLang != "":
|
||||
vars["locale"] = normalizeLang(cookieLang)
|
||||
case acceptLang != "":
|
||||
vars["locale"] = normalizeLang(strings.Split(acceptLang, ",")[0])
|
||||
default:
|
||||
vars["locale"] = defaultLang
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/javascript")
|
||||
for k, v := range vars {
|
||||
fmt.Fprintf(w, "var %s = %q\n", k, v)
|
||||
}
|
||||
}
|
||||
|
||||
func normalizeLang(lang string) string {
|
||||
return strings.ToLower(strings.Split(lang, "-")[0])
|
||||
}
|
||||
|
|
83
src/.eslintrc.js
Normal file
83
src/.eslintrc.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
// https://eslint.org/docs/user-guide/configuring
|
||||
|
||||
module.exports = {
|
||||
'root': true,
|
||||
'parserOptions': {
|
||||
parser: 'babel-eslint',
|
||||
sourceType:'module',
|
||||
},
|
||||
'env': {
|
||||
node: true,
|
||||
},
|
||||
'extends': [
|
||||
// https://github.com/standard/standard/blob/master/docs/RULES-en.md
|
||||
'eslint:recommended',
|
||||
],
|
||||
// required to lint *.vue files
|
||||
'globals': {
|
||||
locale: true,
|
||||
process: true,
|
||||
version: true,
|
||||
},
|
||||
// add your custom rules here
|
||||
'rules': {
|
||||
'array-bracket-newline': ['error', { multiline: true }],
|
||||
'array-bracket-spacing': ['error'],
|
||||
'arrow-body-style': ['error', 'as-needed'],
|
||||
'arrow-parens': ['error', 'as-needed'],
|
||||
'arrow-spacing': ['error', { before: true, after: true }],
|
||||
'block-spacing': ['error'],
|
||||
'brace-style': ['error', '1tbs'],
|
||||
'comma-dangle': ['error', 'always-multiline'], // Apply Contentflow rules
|
||||
'comma-spacing': ['error'],
|
||||
'comma-style': ['error', 'last'],
|
||||
'curly': ['error'],
|
||||
'dot-location': ['error', 'property'],
|
||||
'dot-notation': ['error'],
|
||||
'eol-last': ['error', 'always'],
|
||||
'eqeqeq': ['error', 'always', { 'null': 'ignore' }],
|
||||
'func-call-spacing': ['error', 'never'],
|
||||
'function-paren-newline': ['error', 'multiline'],
|
||||
'generator-star-spacing': ['off'], // allow async-await
|
||||
'implicit-arrow-linebreak': ['error'],
|
||||
'indent': ['error', 2],
|
||||
'key-spacing': ['error', { beforeColon: false, afterColon: true, mode: 'strict' }],
|
||||
'keyword-spacing': ['error'],
|
||||
'linebreak-style': ['error', 'unix'],
|
||||
'lines-between-class-members': ['error'],
|
||||
'multiline-comment-style': ['warn'],
|
||||
'newline-per-chained-call': ['error'],
|
||||
'no-console': ['off'],
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', // allow debugger during development
|
||||
'no-else-return': ['error'],
|
||||
'no-extra-parens': ['error'],
|
||||
'no-implicit-coercion': ['error'],
|
||||
'no-lonely-if': ['error'],
|
||||
'no-multiple-empty-lines': ['warn', { max: 2, maxEOF: 0, maxBOF: 0 }],
|
||||
'no-multi-spaces': ['error'],
|
||||
'no-trailing-spaces': ['error'],
|
||||
'no-unneeded-ternary': ['error'],
|
||||
'no-useless-return': ['error'],
|
||||
'no-whitespace-before-property': ['error'],
|
||||
'object-curly-newline': ['error', { consistent: true }],
|
||||
'object-curly-spacing': ['error', 'always'],
|
||||
'object-shorthand': ['error'],
|
||||
'padded-blocks': ['error', 'never'],
|
||||
'prefer-arrow-callback': ['error'],
|
||||
'prefer-const': ['error'],
|
||||
'prefer-object-spread': ['error'],
|
||||
'prefer-template': ['error'],
|
||||
'quote-props': ['error', 'consistent-as-needed', { keywords: true }],
|
||||
'quotes': ['error', 'single', { allowTemplateLiterals: true }],
|
||||
'semi': ['error', 'never'],
|
||||
'space-before-blocks': ['error', 'always'],
|
||||
'spaced-comment': ['warn', 'always'],
|
||||
'space-infix-ops': ['error'],
|
||||
'space-in-parens': ['error', 'never'],
|
||||
'space-unary-ops': ['error', { words: true, nonwords: false }],
|
||||
'switch-colon-spacing': ['error'],
|
||||
'unicode-bom': ['error', 'never'],
|
||||
'wrap-iife': ['error'],
|
||||
'yoda': ['error'],
|
||||
},
|
||||
}
|
146
src/app.js
146
src/app.js
|
@ -1,146 +0,0 @@
|
|||
let securePassword = null
|
||||
|
||||
// bindResizeTextarea attaches resize triggers to all available text areas
|
||||
function bindResizeTextarea() {
|
||||
$('textarea').each((idx, text) => {
|
||||
let doResize = () => {
|
||||
text.style.height = text.scrollHeight + 'px'
|
||||
}
|
||||
|
||||
let delayedResize = () => {
|
||||
window.setTimeout(doResize, 0)
|
||||
}
|
||||
|
||||
text.setAttribute('style', "height: #{this.scrollHeight}px; min-height: #{this.scrollHeight}px; overflow-y:hidden;")
|
||||
|
||||
$(text)
|
||||
.on('change', doResize)
|
||||
.on('cut', delayedResize)
|
||||
.on('paste', delayedResize)
|
||||
.on('drop', delayedResize)
|
||||
.on('keydown', delayedResize)
|
||||
})
|
||||
}
|
||||
|
||||
// createSecret executes the secret creation after encrypting the secret
|
||||
function createSecret() {
|
||||
let secret = $('#formCreateSecret').find('textarea').val()
|
||||
|
||||
securePassword = Math.random().toString(36).substring(2)
|
||||
secret = GibberishAES.enc(secret, securePassword)
|
||||
|
||||
$.ajax('api/create', {
|
||||
method: "post",
|
||||
data: {
|
||||
secret: secret,
|
||||
},
|
||||
dataType: "json",
|
||||
statusCode: {
|
||||
201: secretCreated,
|
||||
400: somethingWrong,
|
||||
500: somethingWrong,
|
||||
404: () => {
|
||||
// Mock for interface testing
|
||||
secretCreated({
|
||||
secret_id: 'foobar',
|
||||
})
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// dataNotFound displays the not-found error
|
||||
function dataNotFound() {
|
||||
$('#notfound').show()
|
||||
}
|
||||
|
||||
// hashLoad reacts on a changed window hash an starts the diplaying of the secret
|
||||
function hashLoad() {
|
||||
let hash = window.location.hash
|
||||
if (hash.length === 0) return
|
||||
|
||||
$('#cardNewSecret').hide()
|
||||
$('#cardSecretURL').hide()
|
||||
$('#notfound').hide()
|
||||
$('#somethingwrong').hide()
|
||||
$('#cardReadSecretPre').show()
|
||||
}
|
||||
|
||||
// initBinds attaches functions to frontend elements
|
||||
function initBinds() {
|
||||
$('#formCreateSecret').bind('submit', createSecret)
|
||||
$('#newSecret, .navbar-brand').bind('click', newSecret)
|
||||
$(window).bind('hashchange', hashLoad)
|
||||
$('#revealSecret').bind('click', requestSecret)
|
||||
bindResizeTextarea()
|
||||
}
|
||||
|
||||
// newSecret removes the window hash and therefore returns to "new secret" mode
|
||||
function newSecret() {
|
||||
location.href = location.href.split('#')[0]
|
||||
}
|
||||
|
||||
// requestSecret requests the encrypted secret from the backend
|
||||
function requestSecret() {
|
||||
let hash = window.location.hash
|
||||
hash = decodeURIComponent(hash)
|
||||
|
||||
let parts = hash.split('|')
|
||||
if (parts.length === 2) {
|
||||
hash = parts[0]
|
||||
securePassword = parts[1]
|
||||
}
|
||||
|
||||
let id = hash.substring(1)
|
||||
$.ajax(`api/get/${id}`, {
|
||||
dataType: "json",
|
||||
statusCode: {
|
||||
404: dataNotFound,
|
||||
200: showData,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// secretCreated generates the share URLs and displays them to the user
|
||||
function secretCreated(data) {
|
||||
let secretHash = data.secret_id
|
||||
if (securePassword !== null) secretHash = `${secretHash}|${securePassword}`
|
||||
let url = `${location.href.split('#')[0]}#${secretHash}`
|
||||
|
||||
$('#cardNewSecret').hide()
|
||||
$('#cardReadSecretPre').hide()
|
||||
$('#cardSecretURL').show()
|
||||
$('#cardSecretURL').find('input').val(url)
|
||||
$('#cardSecretURL').find('input').focus()
|
||||
$('#cardSecretURL').find('input').select()
|
||||
|
||||
securePassword = null
|
||||
}
|
||||
|
||||
// showData takes the backend answer, decrypts the secret and shows it
|
||||
function showData(data) {
|
||||
let secret = data.secret
|
||||
if (securePassword !== null) secret = GibberishAES.dec(secret, securePassword)
|
||||
|
||||
$('#cardNewSecret').hide()
|
||||
$('#cardSecretURL').hide()
|
||||
$('#notfound').hide()
|
||||
$('#somethingwrong').hide()
|
||||
$('#cardReadSecretPre').hide()
|
||||
$('#cardReadSecret').show()
|
||||
$('#cardReadSecret').find('textarea').val(secret)
|
||||
$('#cardReadSecret').find('textarea').trigger('change')
|
||||
}
|
||||
|
||||
// somethingWrong shows the "something went wrong" screen
|
||||
function somethingWrong() {
|
||||
$('#somethingwrong').show()
|
||||
}
|
||||
|
||||
// Trigger initialization functions
|
||||
$(() => {
|
||||
initBinds()
|
||||
hashLoad()
|
||||
})
|
208
src/app.vue
Normal file
208
src/app.vue
Normal file
|
@ -0,0 +1,208 @@
|
|||
<template>
|
||||
<div id="app">
|
||||
<b-navbar toggleable="lg" type="dark" variant="primary">
|
||||
<b-navbar-brand href="#" @click="newSecret">
|
||||
<i class="fas fa-user-secret"></i> OTS - One Time Secrets
|
||||
</b-navbar-brand>
|
||||
|
||||
<b-navbar-toggle target="nav-collapse"></b-navbar-toggle>
|
||||
|
||||
<b-collapse id="nav-collapse" is-nav>
|
||||
<b-navbar-nav class="ml-auto">
|
||||
<b-nav-item @click="newSecret"><i class="fas fa-plus"></i> {{ $t('btn-new-secret') }}</b-nav-item>
|
||||
</b-navbar-nav>
|
||||
</b-collapse>
|
||||
</b-navbar>
|
||||
|
||||
<b-container class="mt-4">
|
||||
|
||||
<b-row class="justify-content-center">
|
||||
<b-col md="8">
|
||||
<b-alert v-model="showError" variant="danger" dismissible v-html="error"></b-alert>
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row>
|
||||
<b-col>
|
||||
|
||||
<b-card
|
||||
border-variant="primary"
|
||||
header-bg-variant="primary"
|
||||
header-text-variant="white"
|
||||
v-if="mode == 'create' && !secretId"
|
||||
>
|
||||
<span slot="header" v-html="$t('title-new-secret')"></span>
|
||||
<b-form-group :label="$t('label-secret-data')">
|
||||
<b-form-textarea
|
||||
id="secret"
|
||||
max-rows="25"
|
||||
rows="5"
|
||||
v-model="secret"
|
||||
>
|
||||
</b-form-textarea>
|
||||
</b-form-group>
|
||||
<b-button variant="success" @click="createSecret">{{ $t('btn-create-secret') }}</b-button>
|
||||
</b-card>
|
||||
|
||||
<b-card
|
||||
border-variant="success"
|
||||
header-bg-variant="success"
|
||||
header-text-variant="white"
|
||||
v-if="mode == 'create' && secretId"
|
||||
>
|
||||
<span slot="header" v-html="$t('title-secret-created')"></span>
|
||||
<p v-html="$t('text-pre-url')"></p>
|
||||
<b-form-group>
|
||||
<b-form-input :value="secretUrl" readonly></b-form-input>
|
||||
</b-form-group>
|
||||
<p v-html="$t('text-burn-hint')"></p>
|
||||
</b-card>
|
||||
|
||||
<b-card
|
||||
border-variant="primary"
|
||||
header-bg-variant="primary"
|
||||
header-text-variant="white"
|
||||
v-if="mode == 'view'"
|
||||
>
|
||||
<span slot="header" v-html="$t('title-reading-secret')"></span>
|
||||
<template v-if="!secret">
|
||||
<p v-html="$t('text-pre-reveal-hint')"></p>
|
||||
<b-button variant="success" @click=requestSecret>{{ $t('btn-reveal-secret') }}</b-button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<b-form-group>
|
||||
<b-form-textarea
|
||||
max-rows="25"
|
||||
readonly
|
||||
rows="5"
|
||||
:value="secret"
|
||||
>
|
||||
</b-form-textarea>
|
||||
</b-form-group>
|
||||
<p v-html="$t('text-hint-burned')"></p>
|
||||
</template>
|
||||
</b-card>
|
||||
|
||||
</b-col>
|
||||
</b-row>
|
||||
|
||||
<b-row class="mt-5">
|
||||
<b-col class="footer">
|
||||
{{ $t('text-powered-by') }} <a href="https://github.com/Luzifer/ots"><i class="fab fa-github"></i> Luzifer/OTS</a> {{ $root.version }}
|
||||
</b-col>
|
||||
</b-row>
|
||||
</b-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios'
|
||||
import AES from 'gibberish-aes/src/gibberish-aes'
|
||||
|
||||
export default {
|
||||
name: 'app',
|
||||
|
||||
computed: {
|
||||
secretUrl() {
|
||||
return `${window.location.href}#${this.secretId}|${this.securePassword}`
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
error: '',
|
||||
mode: 'create',
|
||||
secret: '',
|
||||
securePassword:'',
|
||||
secretId: '',
|
||||
showError: false,
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
// createSecret executes the secret creation after encrypting the secret
|
||||
createSecret() {
|
||||
this.securePassword = Math.random().toString(36).substring(2)
|
||||
const secret = AES.enc(this.secret, this.securePassword)
|
||||
|
||||
axios.post('api/create', { secret })
|
||||
.then(resp=>{
|
||||
this.secretId = resp.data.secret_id
|
||||
this.secret = ''
|
||||
})
|
||||
.catch(err => {
|
||||
switch (err.response.status) {
|
||||
case 404:
|
||||
// Mock for interface testing
|
||||
this.secretId = 'foobar'
|
||||
break
|
||||
default:
|
||||
this.error = this.$t('alert-something-went-wrong')
|
||||
this.showError = true
|
||||
}
|
||||
})
|
||||
|
||||
return false
|
||||
},
|
||||
|
||||
// hashLoad reacts on a changed window hash an starts the diplaying of the secret
|
||||
hashLoad() {
|
||||
const hash = window.location.hash
|
||||
if (hash.length === 0) return
|
||||
|
||||
const parts = hash.substring(1).split('|')
|
||||
if (parts.length == 2) {
|
||||
this.securePassword = parts[1]
|
||||
}
|
||||
this.secretId = parts[0]
|
||||
this.mode = 'view'
|
||||
},
|
||||
|
||||
// newSecret removes the window hash and therefore returns to "new secret" mode
|
||||
newSecret() {
|
||||
location.href = location.href.split('#')[0]
|
||||
},
|
||||
|
||||
// requestSecret requests the encrypted secret from the backend
|
||||
requestSecret() {
|
||||
axios.get(`api/get/${this.secretId}`)
|
||||
.then(resp => {
|
||||
let secret = resp.data.secret
|
||||
if (this.securePassword) {
|
||||
secret = AES.dec(secret, this.securePassword)
|
||||
}
|
||||
this.secret = secret
|
||||
})
|
||||
.catch(err => {
|
||||
switch(err.response.status) {
|
||||
case 404:
|
||||
this.error = this.$t('alert-secret-not-found')
|
||||
this.showError = true
|
||||
break
|
||||
default:
|
||||
this.error = this.$t('alert-something-went-wrong')
|
||||
this.showError = true
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
// Trigger initialization functions
|
||||
mounted() {
|
||||
window.onhashchange = this.hashLoad
|
||||
this.hashLoad()
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
textarea {
|
||||
font-family: monospace;
|
||||
}
|
||||
.footer {
|
||||
color: #2f2f2f;
|
||||
font-size: 0.9em;
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
38
src/main.js
Normal file
38
src/main.js
Normal file
|
@ -0,0 +1,38 @@
|
|||
import Vue from 'vue'
|
||||
import VueI18n from 'vue-i18n'
|
||||
|
||||
import BootstrapVue from 'bootstrap-vue'
|
||||
|
||||
import 'bootstrap/dist/css/bootstrap.css'
|
||||
import 'bootstrap-vue/dist/bootstrap-vue.css'
|
||||
import 'bootswatch/dist/flatly/bootstrap.css'
|
||||
|
||||
import app from './app.vue'
|
||||
import messages from './langs/langs.js'
|
||||
|
||||
console.log(['app.js loaded',app,messages])
|
||||
|
||||
Vue.use(BootstrapVue)
|
||||
Vue.use(VueI18n)
|
||||
|
||||
const i18n = new VueI18n({
|
||||
locale,
|
||||
fallbackLocale: 'en',
|
||||
messages,
|
||||
})
|
||||
|
||||
new Vue({
|
||||
components: { app },
|
||||
|
||||
data: {
|
||||
error: null,
|
||||
secret: '',
|
||||
securePassword: null,
|
||||
view: 'create',
|
||||
version,
|
||||
},
|
||||
|
||||
el: '#app',
|
||||
i18n,
|
||||
render: createElement => createElement('app'),
|
||||
})
|
351
src/package-lock.json
generated
351
src/package-lock.json
generated
|
@ -3,6 +3,120 @@
|
|||
"requires": true,
|
||||
"lockfileVersion": 1,
|
||||
"dependencies": {
|
||||
"@nuxt/opencollective": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@nuxt/opencollective/-/opencollective-0.2.2.tgz",
|
||||
"integrity": "sha512-ie50SpS47L+0gLsW4yP23zI/PtjsDRglyozX2G09jeiUazC1AJlGPZo0JUs9iuCDUoIgsDEf66y7/bSfig0BpA==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.1",
|
||||
"consola": "^2.3.0",
|
||||
"node-fetch": "^2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@vue/component-compiler-utils": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz",
|
||||
"integrity": "sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"consolidate": "^0.15.1",
|
||||
"hash-sum": "^1.0.2",
|
||||
"lru-cache": "^4.1.2",
|
||||
"merge-source-map": "^1.1.0",
|
||||
"postcss": "^7.0.14",
|
||||
"postcss-selector-parser": "^5.0.0",
|
||||
"prettier": "1.16.3",
|
||||
"source-map": "~0.6.1",
|
||||
"vue-template-es2015-compiler": "^1.9.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss": {
|
||||
"version": "7.0.16",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.16.tgz",
|
||||
"integrity": "sha512-MOo8zNSlIqh22Uaa3drkdIAgUGEL+AD1ESiSdmElLUmE2uVDo1QloiT/IfW9qRw8Gw+Y/w69UVMGwbufMSftxA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"chalk": "^2.4.2",
|
||||
"source-map": "^0.6.1",
|
||||
"supports-color": "^6.1.0"
|
||||
}
|
||||
},
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
|
||||
"integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@webassemblyjs/ast": {
|
||||
"version": "1.8.5",
|
||||
"resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz",
|
||||
|
@ -419,6 +533,15 @@
|
|||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
|
||||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.0.tgz",
|
||||
"integrity": "sha1-MtU+SFHv3AoRmTts0AB4nXDAUQI=",
|
||||
"requires": {
|
||||
"follow-redirects": "^1.3.0",
|
||||
"is-buffer": "^1.1.5"
|
||||
}
|
||||
},
|
||||
"babel-code-frame": {
|
||||
"version": "6.26.0",
|
||||
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||
|
@ -1152,6 +1275,29 @@
|
|||
"integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==",
|
||||
"dev": true
|
||||
},
|
||||
"bootstrap": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
|
||||
"integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag=="
|
||||
},
|
||||
"bootstrap-vue": {
|
||||
"version": "2.0.0-rc.19",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-vue/-/bootstrap-vue-2.0.0-rc.19.tgz",
|
||||
"integrity": "sha512-OCbRwqKb0F+RGr162m+RyKI4yNM0VjfxOGI32CMgHfCnnc0MZ0wF2Svg2E3Q7AWCq0N8LgD/EsF/K7Vg3kdDyw==",
|
||||
"requires": {
|
||||
"@nuxt/opencollective": "^0.2.2",
|
||||
"bootstrap": "^4.3.1",
|
||||
"core-js": ">=2.6.5 <3.0.0",
|
||||
"popper.js": "^1.15.0",
|
||||
"portal-vue": "^2.1.1",
|
||||
"vue-functional-data-merge": "^2.0.7"
|
||||
}
|
||||
},
|
||||
"bootswatch": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-4.3.1.tgz",
|
||||
"integrity": "sha512-kNdpo/TnhO++aic1IODLIe1V0lx6pXwHMpwXMacpANDnuVDtgU1MUgUbVMC3rSWm4UcbImfwPraNYgjKDT0BtA=="
|
||||
},
|
||||
"brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
|
@ -1521,7 +1667,6 @@
|
|||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
|
@ -1529,8 +1674,7 @@
|
|||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.7",
|
||||
|
@ -1577,6 +1721,11 @@
|
|||
"typedarray": "^0.0.6"
|
||||
}
|
||||
},
|
||||
"consola": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/consola/-/consola-2.6.1.tgz",
|
||||
"integrity": "sha512-vt35owQG6OxYDJVaViQ4aFgOK+b98hIvs+R5CWkKgpO8rTPyaYwlMadZ7oZcjnWz1/+u4czDnrcogFr5AtrRug=="
|
||||
},
|
||||
"console-browserify": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
|
||||
|
@ -1592,6 +1741,15 @@
|
|||
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
|
||||
"dev": true
|
||||
},
|
||||
"consolidate": {
|
||||
"version": "0.15.1",
|
||||
"resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz",
|
||||
"integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"constants-browserify": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
|
||||
|
@ -1630,8 +1788,7 @@
|
|||
"core-js": {
|
||||
"version": "2.6.5",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.5.tgz",
|
||||
"integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A=="
|
||||
},
|
||||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
|
@ -1785,6 +1942,12 @@
|
|||
"integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
|
||||
"dev": true
|
||||
},
|
||||
"de-indent": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
|
||||
"integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=",
|
||||
"dev": true
|
||||
},
|
||||
"debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
|
@ -1991,8 +2154,7 @@
|
|||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
|
||||
"dev": true
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "4.0.3",
|
||||
|
@ -2313,6 +2475,29 @@
|
|||
"readable-stream": "^2.3.6"
|
||||
}
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
|
||||
"integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
|
||||
"requires": {
|
||||
"debug": "^3.2.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
"version": "3.2.6",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
|
||||
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"for-in": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
|
||||
|
@ -3003,6 +3188,11 @@
|
|||
"assert-plus": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"gibberish-aes": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/gibberish-aes/-/gibberish-aes-1.0.0.tgz",
|
||||
"integrity": "sha1-9kHEWPuCLgrWHDwN6hWOC5Q+n8U="
|
||||
},
|
||||
"glob": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
|
||||
|
@ -3113,8 +3303,7 @@
|
|||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"has-unicode": {
|
||||
"version": "2.0.1",
|
||||
|
@ -3164,6 +3353,12 @@
|
|||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"hash-sum": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
|
||||
"integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=",
|
||||
"dev": true
|
||||
},
|
||||
"hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
|
@ -3174,6 +3369,12 @@
|
|||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"he": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
|
||||
"integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
|
||||
"dev": true
|
||||
},
|
||||
"hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
|
@ -3345,6 +3546,12 @@
|
|||
"repeating": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"indexes-of": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
|
||||
"integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
|
||||
"dev": true
|
||||
},
|
||||
"indexof": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
|
||||
|
@ -3432,8 +3639,7 @@
|
|||
"is-buffer": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
|
||||
"dev": true
|
||||
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
|
||||
},
|
||||
"is-data-descriptor": {
|
||||
"version": "0.1.4",
|
||||
|
@ -3880,6 +4086,23 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"merge-source-map": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.1.0.tgz",
|
||||
"integrity": "sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"source-map": "^0.6.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"micromatch": {
|
||||
"version": "3.1.10",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
|
||||
|
@ -4088,6 +4311,11 @@
|
|||
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.5.0.tgz",
|
||||
"integrity": "sha512-YuZKluhWGJwCcUu4RlZstdAxr8bFfOVHakc1mplwHkk8J+tqM1Y5yraYvIUpeX8aY7+crCwiELJq7Vl0o0LWXw=="
|
||||
},
|
||||
"node-gyp": {
|
||||
"version": "3.8.0",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
|
||||
|
@ -4539,6 +4767,16 @@
|
|||
"find-up": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"popper.js": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz",
|
||||
"integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA=="
|
||||
},
|
||||
"portal-vue": {
|
||||
"version": "2.1.4",
|
||||
"resolved": "https://registry.npmjs.org/portal-vue/-/portal-vue-2.1.4.tgz",
|
||||
"integrity": "sha512-Mr2h+RvoOOGHS7N0E3QPP+UQMt1OhSjQ7eMSGTXqkLiO0AjGEDw2x4kzmHATsZfDqQumiaYSDRzlUP2By3lvsA=="
|
||||
},
|
||||
"posix-character-classes": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
|
||||
|
@ -4632,12 +4870,37 @@
|
|||
"postcss": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"postcss-selector-parser": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz",
|
||||
"integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssesc": "^2.0.0",
|
||||
"indexes-of": "^1.0.1",
|
||||
"uniq": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"cssesc": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz",
|
||||
"integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"postcss-value-parser": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
|
||||
"dev": true
|
||||
},
|
||||
"prettier": {
|
||||
"version": "1.16.3",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz",
|
||||
"integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==",
|
||||
"dev": true
|
||||
},
|
||||
"private": {
|
||||
"version": "0.1.8",
|
||||
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
|
||||
|
@ -5941,6 +6204,12 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"uniq": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
|
||||
"integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
|
||||
"dev": true
|
||||
},
|
||||
"unique-filename": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz",
|
||||
|
@ -6101,6 +6370,66 @@
|
|||
"indexof": "0.0.1"
|
||||
}
|
||||
},
|
||||
"vue": {
|
||||
"version": "2.6.10",
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-2.6.10.tgz",
|
||||
"integrity": "sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ=="
|
||||
},
|
||||
"vue-functional-data-merge": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/vue-functional-data-merge/-/vue-functional-data-merge-2.0.7.tgz",
|
||||
"integrity": "sha512-pvLc+H+x2prwBj/uSEIITyxjz/7ZUVVK8uYbrYMmhDvMXnzh9OvQvVEwcOSBQjsubd4Eq41/CSJaWzy4hemMNQ=="
|
||||
},
|
||||
"vue-hot-reload-api": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-2.3.3.tgz",
|
||||
"integrity": "sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g==",
|
||||
"dev": true
|
||||
},
|
||||
"vue-i18n": {
|
||||
"version": "8.11.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-8.11.2.tgz",
|
||||
"integrity": "sha512-STcpmxqBrG77SyWi7e0Yn/B3DjKR6mSDwYS4F/V7zoi+e/+CPbVb2TaBqFwnrkoDcPmRfjM7nTwsiRQQOGdifw=="
|
||||
},
|
||||
"vue-loader": {
|
||||
"version": "15.7.0",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-15.7.0.tgz",
|
||||
"integrity": "sha512-x+NZ4RIthQOxcFclEcs8sXGEWqnZHodL2J9Vq+hUz+TDZzBaDIh1j3d9M2IUlTjtrHTZy4uMuRdTi8BGws7jLA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@vue/component-compiler-utils": "^2.5.1",
|
||||
"hash-sum": "^1.0.2",
|
||||
"loader-utils": "^1.1.0",
|
||||
"vue-hot-reload-api": "^2.3.0",
|
||||
"vue-style-loader": "^4.1.0"
|
||||
}
|
||||
},
|
||||
"vue-style-loader": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
|
||||
"integrity": "sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"hash-sum": "^1.0.2",
|
||||
"loader-utils": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"vue-template-compiler": {
|
||||
"version": "2.6.10",
|
||||
"resolved": "https://registry.npmjs.org/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz",
|
||||
"integrity": "sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"de-indent": "^1.0.2",
|
||||
"he": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"vue-template-es2015-compiler": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz",
|
||||
"integrity": "sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==",
|
||||
"dev": true
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz",
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
"node-sass": "^4.9.2",
|
||||
"sass-loader": "^7.0.3",
|
||||
"style-loader": "^0.21.0",
|
||||
"vue-loader": "^15.7.0",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
"webpack": "^4.16.2",
|
||||
"webpack-cli": "^3.1.0",
|
||||
"webpack-dev-middleware": "^1.4.0",
|
||||
|
@ -16,5 +18,15 @@
|
|||
"private": true,
|
||||
"scripts": {
|
||||
"build": "webpack -p"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"bootstrap": "^4.3.1",
|
||||
"bootstrap-vue": "^2.0.0-rc.19",
|
||||
"bootswatch": "^4.3.1",
|
||||
"gibberish-aes": "^1.0.0",
|
||||
"popper.js": "^1.15.0",
|
||||
"vue": "^2.6.10",
|
||||
"vue-i18n": "^8.11.2"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
const path = require('path')
|
||||
const webpack = require('webpack');
|
||||
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin')
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, dir)
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
entry: './app.js',
|
||||
entry: './main.js',
|
||||
output: {
|
||||
filename: 'app.js',
|
||||
path: path.resolve(__dirname, '..', 'frontend')
|
||||
|
@ -17,13 +19,16 @@ module.exports = {
|
|||
'process.env': {
|
||||
'NODE_ENV': JSON.stringify('production')
|
||||
}
|
||||
})
|
||||
}),
|
||||
new VueLoaderPlugin(),
|
||||
],
|
||||
optimization: {
|
||||
minimize: true
|
||||
},
|
||||
module: {
|
||||
rules: [{
|
||||
rules: [
|
||||
|
||||
{
|
||||
test: /\.(s?)css$/,
|
||||
use: [
|
||||
'style-loader',
|
||||
|
@ -31,6 +36,7 @@ module.exports = {
|
|||
'sass-loader',
|
||||
],
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /(node_modules|bower_components)/,
|
||||
|
@ -38,15 +44,17 @@ module.exports = {
|
|||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: [
|
||||
['env', {
|
||||
"targets": {
|
||||
"browsers": [">0.25%", "not ie 11", "not op_mini all"]
|
||||
}
|
||||
}]
|
||||
['env', { "targets": { "browsers": [">0.25%", "not ie 11", "not op_mini all"] } }]
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
},
|
||||
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue