@ -0,0 +1,30 @@
|
|||||||
|
{
|
||||||
|
"comments": false,
|
||||||
|
"env": {
|
||||||
|
"main": {
|
||||||
|
"presets": [
|
||||||
|
["env", {
|
||||||
|
"targets": { "node": 7 }
|
||||||
|
}],
|
||||||
|
"stage-0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"renderer": {
|
||||||
|
"presets": [
|
||||||
|
["env", {
|
||||||
|
"modules": false
|
||||||
|
}],
|
||||||
|
"stage-0"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"web": {
|
||||||
|
"presets": [
|
||||||
|
["env", {
|
||||||
|
"modules": false
|
||||||
|
}],
|
||||||
|
"stage-0"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"plugins": ["transform-runtime"]
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
process.env.NODE_ENV = 'production'
|
||||||
|
|
||||||
|
const { say } = require('cfonts')
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const del = require('del')
|
||||||
|
const { spawn } = require('child_process')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const Multispinner = require('multispinner')
|
||||||
|
|
||||||
|
|
||||||
|
const mainConfig = require('./webpack.main.config')
|
||||||
|
const rendererConfig = require('./webpack.renderer.config')
|
||||||
|
const webConfig = require('./webpack.web.config')
|
||||||
|
|
||||||
|
const doneLog = chalk.bgGreen.white(' DONE ') + ' '
|
||||||
|
const errorLog = chalk.bgRed.white(' ERROR ') + ' '
|
||||||
|
const okayLog = chalk.bgBlue.white(' OKAY ') + ' '
|
||||||
|
const isCI = process.env.CI || false
|
||||||
|
|
||||||
|
if (process.env.BUILD_TARGET === 'clean') clean()
|
||||||
|
else if (process.env.BUILD_TARGET === 'web') web()
|
||||||
|
else build()
|
||||||
|
|
||||||
|
function clean () {
|
||||||
|
del.sync(['build/*', '!build/icons', '!build/icons/icon.*'])
|
||||||
|
console.log(`\n${doneLog}\n`)
|
||||||
|
process.exit()
|
||||||
|
}
|
||||||
|
|
||||||
|
function build () {
|
||||||
|
greeting()
|
||||||
|
|
||||||
|
del.sync(['dist/electron/*', '!.gitkeep'])
|
||||||
|
|
||||||
|
const tasks = ['main', 'renderer']
|
||||||
|
const m = new Multispinner(tasks, {
|
||||||
|
preText: 'building',
|
||||||
|
postText: 'process'
|
||||||
|
})
|
||||||
|
|
||||||
|
let results = ''
|
||||||
|
|
||||||
|
m.on('success', () => {
|
||||||
|
process.stdout.write('\x1B[2J\x1B[0f')
|
||||||
|
console.log(`\n\n${results}`)
|
||||||
|
console.log(`${okayLog}take it away ${chalk.yellow('`electron-builder`')}\n`)
|
||||||
|
process.exit()
|
||||||
|
})
|
||||||
|
|
||||||
|
pack(mainConfig).then(result => {
|
||||||
|
results += result + '\n\n'
|
||||||
|
m.success('main')
|
||||||
|
}).catch(err => {
|
||||||
|
m.error('main')
|
||||||
|
console.log(`\n ${errorLog}failed to build main process`)
|
||||||
|
console.error(`\n${err}\n`)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
pack(rendererConfig).then(result => {
|
||||||
|
results += result + '\n\n'
|
||||||
|
m.success('renderer')
|
||||||
|
}).catch(err => {
|
||||||
|
m.error('renderer')
|
||||||
|
console.log(`\n ${errorLog}failed to build renderer process`)
|
||||||
|
console.error(`\n${err}\n`)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function pack (config) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
webpack(config, (err, stats) => {
|
||||||
|
if (err) reject(err.stack || err)
|
||||||
|
else if (stats.hasErrors()) {
|
||||||
|
let err = ''
|
||||||
|
|
||||||
|
stats.toString({
|
||||||
|
chunks: false,
|
||||||
|
colors: true
|
||||||
|
})
|
||||||
|
.split(/\r?\n/)
|
||||||
|
.forEach(line => {
|
||||||
|
err += ` ${line}\n`
|
||||||
|
})
|
||||||
|
|
||||||
|
reject(err)
|
||||||
|
} else {
|
||||||
|
resolve(stats.toString({
|
||||||
|
chunks: false,
|
||||||
|
colors: true
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function web () {
|
||||||
|
del.sync(['dist/web/*', '!.gitkeep'])
|
||||||
|
webpack(webConfig, (err, stats) => {
|
||||||
|
if (err || stats.hasErrors()) console.log(err)
|
||||||
|
|
||||||
|
console.log(stats.toString({
|
||||||
|
chunks: false,
|
||||||
|
colors: true
|
||||||
|
}))
|
||||||
|
|
||||||
|
process.exit()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function greeting () {
|
||||||
|
console.log('WOW such build\n');
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
const hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true')
|
||||||
|
|
||||||
|
hotClient.subscribe(event => {
|
||||||
|
/**
|
||||||
|
* Reload browser when HTMLWebpackPlugin emits a new index.html
|
||||||
|
*
|
||||||
|
* Currently disabled until jantimon/html-webpack-plugin#680 is resolved.
|
||||||
|
* https://github.com/SimulatedGREG/electron-vue/issues/437
|
||||||
|
* https://github.com/jantimon/html-webpack-plugin/issues/680
|
||||||
|
*/
|
||||||
|
// if (event.action === 'reload') {
|
||||||
|
// window.location.reload()
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Notify `mainWindow` when `main` process is compiling,
|
||||||
|
* giving notice for an expected reload of the `electron` process
|
||||||
|
*/
|
||||||
|
if (event.action === 'compiling') {
|
||||||
|
document.body.innerHTML += `
|
||||||
|
<style>
|
||||||
|
#dev-client {
|
||||||
|
background: #4fc08d;
|
||||||
|
border-radius: 4px;
|
||||||
|
bottom: 20px;
|
||||||
|
box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.3);
|
||||||
|
color: #fff;
|
||||||
|
font-family: 'Source Sans Pro', sans-serif;
|
||||||
|
left: 20px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div id="dev-client">
|
||||||
|
Compiling Main Process...
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
})
|
@ -0,0 +1,164 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
const chalk = require('chalk')
|
||||||
|
const electron = require('electron')
|
||||||
|
const path = require('path')
|
||||||
|
const { say } = require('cfonts')
|
||||||
|
const { spawn } = require('child_process')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
const WebpackDevServer = require('webpack-dev-server')
|
||||||
|
const webpackHotMiddleware = require('webpack-hot-middleware')
|
||||||
|
|
||||||
|
const mainConfig = require('./webpack.main.config')
|
||||||
|
const rendererConfig = require('./webpack.renderer.config')
|
||||||
|
|
||||||
|
let electronProcess = null
|
||||||
|
let manualRestart = false
|
||||||
|
let hotMiddleware
|
||||||
|
|
||||||
|
function logStats (proc, data) {
|
||||||
|
let log = ''
|
||||||
|
|
||||||
|
log += chalk.yellow.bold(`┏ ${proc} Process ${new Array((19 - proc.length) + 1).join('-')}`)
|
||||||
|
log += '\n\n'
|
||||||
|
|
||||||
|
if (typeof data === 'object') {
|
||||||
|
data.toString({
|
||||||
|
colors: true,
|
||||||
|
chunks: false
|
||||||
|
}).split(/\r?\n/).forEach(line => {
|
||||||
|
log += ' ' + line + '\n'
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
log += ` ${data}\n`
|
||||||
|
}
|
||||||
|
|
||||||
|
log += '\n' + chalk.yellow.bold(`┗ ${new Array(28 + 1).join('-')}`) + '\n'
|
||||||
|
|
||||||
|
console.log(log)
|
||||||
|
}
|
||||||
|
|
||||||
|
function startRenderer () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
rendererConfig.entry.renderer = [path.join(__dirname, 'dev-client')].concat(rendererConfig.entry.renderer)
|
||||||
|
|
||||||
|
const compiler = webpack(rendererConfig)
|
||||||
|
hotMiddleware = webpackHotMiddleware(compiler, {
|
||||||
|
log: false,
|
||||||
|
heartbeat: 2500
|
||||||
|
})
|
||||||
|
|
||||||
|
compiler.plugin('compilation', compilation => {
|
||||||
|
compilation.plugin('html-webpack-plugin-after-emit', (data, cb) => {
|
||||||
|
hotMiddleware.publish({ action: 'reload' })
|
||||||
|
cb()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
compiler.plugin('done', stats => {
|
||||||
|
logStats('Renderer', stats)
|
||||||
|
})
|
||||||
|
|
||||||
|
const server = new WebpackDevServer(
|
||||||
|
compiler,
|
||||||
|
{
|
||||||
|
contentBase: path.join(__dirname, '../'),
|
||||||
|
quiet: true,
|
||||||
|
before (app, ctx) {
|
||||||
|
app.use(hotMiddleware)
|
||||||
|
ctx.middleware.waitUntilValid(() => {
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
server.listen(9080)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function startMain () {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
mainConfig.entry.main = [path.join(__dirname, '../src/main/index.dev.js')].concat(mainConfig.entry.main)
|
||||||
|
|
||||||
|
const compiler = webpack(mainConfig)
|
||||||
|
|
||||||
|
compiler.plugin('watch-run', (compilation, done) => {
|
||||||
|
logStats('Main', chalk.white.bold('compiling...'))
|
||||||
|
hotMiddleware.publish({ action: 'compiling' })
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
|
||||||
|
compiler.watch({}, (err, stats) => {
|
||||||
|
if (err) {
|
||||||
|
console.log(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logStats('Main', stats)
|
||||||
|
|
||||||
|
if (electronProcess && electronProcess.kill) {
|
||||||
|
manualRestart = true
|
||||||
|
process.kill(electronProcess.pid)
|
||||||
|
electronProcess = null
|
||||||
|
startElectron()
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
manualRestart = false
|
||||||
|
}, 5000)
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function startElectron () {
|
||||||
|
electronProcess = spawn(electron, ['--inspect=5858', '.'])
|
||||||
|
|
||||||
|
electronProcess.stdout.on('data', data => {
|
||||||
|
electronLog(data, 'blue')
|
||||||
|
})
|
||||||
|
electronProcess.stderr.on('data', data => {
|
||||||
|
electronLog(data, 'red')
|
||||||
|
})
|
||||||
|
|
||||||
|
electronProcess.on('close', () => {
|
||||||
|
if (!manualRestart) process.exit()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function electronLog (data, color) {
|
||||||
|
let log = ''
|
||||||
|
data = data.toString().split(/\r?\n/)
|
||||||
|
data.forEach(line => {
|
||||||
|
log += ` ${line}\n`
|
||||||
|
})
|
||||||
|
if (/[0-9A-z]+/.test(log)) {
|
||||||
|
console.log(
|
||||||
|
chalk[color].bold('┏ Electron -------------------') +
|
||||||
|
'\n\n' +
|
||||||
|
log +
|
||||||
|
chalk[color].bold('┗ ----------------------------') +
|
||||||
|
'\n'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function greeting () {
|
||||||
|
console.log('WOW dev 8======) _ __ ___ __\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
function init () {
|
||||||
|
greeting()
|
||||||
|
|
||||||
|
Promise.all([startRenderer(), startMain()])
|
||||||
|
.then(() => {
|
||||||
|
startElectron()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
init()
|
@ -0,0 +1,72 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
process.env.BABEL_ENV = 'main'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const { dependencies } = require('../package.json')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
|
||||||
|
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
||||||
|
|
||||||
|
let mainConfig = {
|
||||||
|
entry: {
|
||||||
|
main: path.join(__dirname, '../src/main/index.js')
|
||||||
|
},
|
||||||
|
externals: [
|
||||||
|
...Object.keys(dependencies || {})
|
||||||
|
],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
use: 'babel-loader',
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.node$/,
|
||||||
|
use: 'node-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
__dirname: process.env.NODE_ENV !== 'production',
|
||||||
|
__filename: process.env.NODE_ENV !== 'production'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
libraryTarget: 'commonjs2',
|
||||||
|
path: path.join(__dirname, '../dist/electron')
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new webpack.NoEmitOnErrorsPlugin()
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
extensions: ['.js', '.json', '.node']
|
||||||
|
},
|
||||||
|
target: 'electron-main'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust mainConfig for development settings
|
||||||
|
*/
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
mainConfig.plugins.push(
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust mainConfig for production settings
|
||||||
|
*/
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
mainConfig.plugins.push(
|
||||||
|
new BabiliWebpackPlugin(),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.NODE_ENV': '"production"'
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = mainConfig
|
@ -0,0 +1,167 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
process.env.BABEL_ENV = 'renderer'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const { dependencies } = require('../package.json')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
|
||||||
|
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of node_modules to include in webpack bundle
|
||||||
|
*
|
||||||
|
* Required for specific packages like Vue UI libraries
|
||||||
|
* that provide pure *.vue files that need compiling
|
||||||
|
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/webpack-configurations.html#white-listing-externals
|
||||||
|
*/
|
||||||
|
let whiteListedModules = ['vue']
|
||||||
|
|
||||||
|
let rendererConfig = {
|
||||||
|
devtool: '#cheap-module-eval-source-map',
|
||||||
|
entry: {
|
||||||
|
renderer: path.join(__dirname, '../src/renderer/main.js')
|
||||||
|
},
|
||||||
|
externals: [
|
||||||
|
...Object.keys(dependencies || {}).filter(d => !whiteListedModules.includes(d))
|
||||||
|
],
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ExtractTextPlugin.extract({
|
||||||
|
fallback: 'style-loader',
|
||||||
|
use: 'css-loader'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: 'vue-html-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
use: 'babel-loader',
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.node$/,
|
||||||
|
use: 'node-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
use: {
|
||||||
|
loader: 'vue-loader',
|
||||||
|
options: {
|
||||||
|
extractCSS: process.env.NODE_ENV === 'production',
|
||||||
|
loaders: {
|
||||||
|
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
||||||
|
scss: 'vue-style-loader!css-loader!sass-loader'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'url-loader',
|
||||||
|
query: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'imgs/[name]--[folder].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'media/[name]--[folder].[ext]'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'url-loader',
|
||||||
|
query: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'fonts/[name]--[folder].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
node: {
|
||||||
|
__dirname: process.env.NODE_ENV !== 'production',
|
||||||
|
__filename: process.env.NODE_ENV !== 'production'
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new ExtractTextPlugin('styles.css'),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: 'index.html',
|
||||||
|
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||||
|
minify: {
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeAttributeQuotes: true,
|
||||||
|
removeComments: true
|
||||||
|
},
|
||||||
|
nodeModules: process.env.NODE_ENV !== 'production'
|
||||||
|
? path.resolve(__dirname, '../node_modules')
|
||||||
|
: false
|
||||||
|
}),
|
||||||
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new webpack.NoEmitOnErrorsPlugin()
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
libraryTarget: 'commonjs2',
|
||||||
|
path: path.join(__dirname, '../dist/electron')
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.join(__dirname, '../src/renderer'),
|
||||||
|
'vue$': 'vue/dist/vue.esm.js'
|
||||||
|
},
|
||||||
|
extensions: ['.js', '.vue', '.json', '.css', '.node']
|
||||||
|
},
|
||||||
|
target: 'electron-renderer'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust rendererConfig for development settings
|
||||||
|
*/
|
||||||
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
|
rendererConfig.plugins.push(
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'__static': `"${path.join(__dirname, '../static').replace(/\\/g, '\\\\')}"`
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust rendererConfig for production settings
|
||||||
|
*/
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
rendererConfig.devtool = ''
|
||||||
|
|
||||||
|
rendererConfig.plugins.push(
|
||||||
|
new BabiliWebpackPlugin(),
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
{
|
||||||
|
from: path.join(__dirname, '../static'),
|
||||||
|
to: path.join(__dirname, '../dist/electron/static'),
|
||||||
|
ignore: ['.*']
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.NODE_ENV': '"production"'
|
||||||
|
}),
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
minimize: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = rendererConfig
|
@ -0,0 +1,128 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
process.env.BABEL_ENV = 'web'
|
||||||
|
|
||||||
|
const path = require('path')
|
||||||
|
const webpack = require('webpack')
|
||||||
|
|
||||||
|
const BabiliWebpackPlugin = require('babili-webpack-plugin')
|
||||||
|
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||||
|
|
||||||
|
let webConfig = {
|
||||||
|
devtool: '#cheap-module-eval-source-map',
|
||||||
|
entry: {
|
||||||
|
web: path.join(__dirname, '../src/renderer/main.js')
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: ExtractTextPlugin.extract({
|
||||||
|
fallback: 'style-loader',
|
||||||
|
use: 'css-loader'
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: 'vue-html-loader'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js$/,
|
||||||
|
use: 'babel-loader',
|
||||||
|
include: [ path.resolve(__dirname, '../src/renderer') ],
|
||||||
|
exclude: /node_modules/
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.vue$/,
|
||||||
|
use: {
|
||||||
|
loader: 'vue-loader',
|
||||||
|
options: {
|
||||||
|
extractCSS: true,
|
||||||
|
loaders: {
|
||||||
|
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
|
||||||
|
scss: 'vue-style-loader!css-loader!sass-loader'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'url-loader',
|
||||||
|
query: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'imgs/[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||||
|
use: {
|
||||||
|
loader: 'url-loader',
|
||||||
|
query: {
|
||||||
|
limit: 10000,
|
||||||
|
name: 'fonts/[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new ExtractTextPlugin('styles.css'),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: 'index.html',
|
||||||
|
template: path.resolve(__dirname, '../src/index.ejs'),
|
||||||
|
minify: {
|
||||||
|
collapseWhitespace: true,
|
||||||
|
removeAttributeQuotes: true,
|
||||||
|
removeComments: true
|
||||||
|
},
|
||||||
|
nodeModules: false
|
||||||
|
}),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.IS_WEB': 'true'
|
||||||
|
}),
|
||||||
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
|
new webpack.NoEmitOnErrorsPlugin()
|
||||||
|
],
|
||||||
|
output: {
|
||||||
|
filename: '[name].js',
|
||||||
|
path: path.join(__dirname, '../dist/web')
|
||||||
|
},
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': path.join(__dirname, '../src/renderer'),
|
||||||
|
'vue$': 'vue/dist/vue.esm.js'
|
||||||
|
},
|
||||||
|
extensions: ['.js', '.vue', '.json', '.css']
|
||||||
|
},
|
||||||
|
target: 'web'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adjust webConfig for production settings
|
||||||
|
*/
|
||||||
|
if (process.env.NODE_ENV === 'production') {
|
||||||
|
webConfig.devtool = ''
|
||||||
|
|
||||||
|
webConfig.plugins.push(
|
||||||
|
new BabiliWebpackPlugin(),
|
||||||
|
new CopyWebpackPlugin([
|
||||||
|
{
|
||||||
|
from: path.join(__dirname, '../static'),
|
||||||
|
to: path.join(__dirname, '../dist/web/static'),
|
||||||
|
ignore: ['.*']
|
||||||
|
}
|
||||||
|
]),
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
'process.env.NODE_ENV': '"production"'
|
||||||
|
}),
|
||||||
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
minimize: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = webConfig
|
@ -0,0 +1,10 @@
|
|||||||
|
.DS_Store
|
||||||
|
dist/electron/*
|
||||||
|
dist/web/*
|
||||||
|
build/*
|
||||||
|
!build/icons
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log
|
||||||
|
npm-debug.log.*
|
||||||
|
thumbs.db
|
||||||
|
!.gitkeep
|
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 15 KiB |
@ -0,0 +1,179 @@
|
|||||||
|
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||||
|
index c3dc88b..db29b09 100644
|
||||||
|
--- a/CMakeLists.txt
|
||||||
|
+++ b/CMakeLists.txt
|
||||||
|
@@ -425,8 +425,6 @@ if(STATIC AND NOT IOS)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
-find_package(PCSC)
|
||||||
|
-
|
||||||
|
add_definition_if_library_exists(c memset_s "string.h" HAVE_MEMSET_S)
|
||||||
|
add_definition_if_library_exists(c explicit_bzero "strings.h" HAVE_EXPLICIT_BZERO)
|
||||||
|
add_definition_if_function_found(strptime HAVE_STRPTIME)
|
||||||
|
@@ -466,14 +464,8 @@ endif()
|
||||||
|
include_directories(${LIBUNWIND_INCLUDE})
|
||||||
|
link_directories(${LIBUNWIND_LIBRARY_DIRS})
|
||||||
|
|
||||||
|
-# Final setup for libpcsc
|
||||||
|
-if (PCSC_FOUND)
|
||||||
|
- message(STATUS "Using PCSC include dir at ${PCSC_INCLUDE_DIR}")
|
||||||
|
- add_definitions(-DHAVE_PCSC)
|
||||||
|
- include_directories(${PCSC_INCLUDE_DIR})
|
||||||
|
- link_directories(${LIBPCSC_LIBRARY_DIRS})
|
||||||
|
-else (PCSC_FOUND)
|
||||||
|
- message(STATUS "Could not find PCSC")
|
||||||
|
+if(USE_DEVICE_LEDGER)
|
||||||
|
+ set(USE_DEVICE_LEDGER 0)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
@@ -904,32 +896,6 @@ endif()
|
||||||
|
add_subdirectory(contrib)
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
-if(BUILD_TESTS)
|
||||||
|
- add_subdirectory(tests)
|
||||||
|
-endif()
|
||||||
|
-
|
||||||
|
-if(BUILD_DOCUMENTATION)
|
||||||
|
- set(DOC_GRAPHS "YES" CACHE STRING "Create dependency graphs (needs graphviz)")
|
||||||
|
- set(DOC_FULLGRAPHS "NO" CACHE STRING "Create call/callee graphs (large)")
|
||||||
|
-
|
||||||
|
- find_program(DOT_PATH dot)
|
||||||
|
-
|
||||||
|
- if (DOT_PATH STREQUAL "DOT_PATH-NOTFOUND")
|
||||||
|
- message("Doxygen: graphviz not found - graphs disabled")
|
||||||
|
- set(DOC_GRAPHS "NO")
|
||||||
|
- endif()
|
||||||
|
-
|
||||||
|
- find_package(Doxygen)
|
||||||
|
- if(DOXYGEN_FOUND)
|
||||||
|
- configure_file("cmake/Doxyfile.in" "Doxyfile" @ONLY)
|
||||||
|
- configure_file("cmake/Doxygen.extra.css.in" "Doxygen.extra.css" @ONLY)
|
||||||
|
- add_custom_target(doc
|
||||||
|
- ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/Doxyfile
|
||||||
|
- WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
- COMMENT "Generating API documentation with Doxygen.." VERBATIM)
|
||||||
|
- endif()
|
||||||
|
-endif()
|
||||||
|
-
|
||||||
|
# when ON - will install libwallet_merged into "lib"
|
||||||
|
option(BUILD_GUI_DEPS "Build GUI dependencies." OFF)
|
||||||
|
|
||||||
|
diff --git a/Makefile b/Makefile
|
||||||
|
index b725d18..abc48c9 100644
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -70,6 +70,10 @@ release-static:
|
||||||
|
mkdir -p build/release
|
||||||
|
cd build/release && cmake -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||||
|
|
||||||
|
+release-light:
|
||||||
|
+ mkdir -p build/release
|
||||||
|
+ cd build/release && cmake -D USE_DEVICE_LEDGER=0 -D STATIC=ON -D ARCH="x86-64" -D BUILD_64=ON -D CMAKE_BUILD_TYPE=release ../.. && $(MAKE)
|
||||||
|
+
|
||||||
|
coverage:
|
||||||
|
mkdir -p build/debug
|
||||||
|
cd build/debug && cmake -D BUILD_TESTS=ON -D CMAKE_BUILD_TYPE=Debug -D COVERAGE=ON ../.. && $(MAKE) && $(MAKE) test
|
||||||
|
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
|
||||||
|
index d2acf51..c2b6f95 100755
|
||||||
|
--- a/src/simplewallet/simplewallet.cpp
|
||||||
|
+++ b/src/simplewallet/simplewallet.cpp
|
||||||
|
@@ -4169,37 +4169,8 @@ bool simple_wallet::try_connect_to_daemon(bool silent, uint32_t* version)
|
||||||
|
std::string simple_wallet::get_mnemonic_language()
|
||||||
|
{
|
||||||
|
std::vector<std::string> language_list;
|
||||||
|
- std::string language_choice;
|
||||||
|
- int language_number = -1;
|
||||||
|
crypto::ElectrumWords::get_language_list(language_list, m_use_english_language_names);
|
||||||
|
- std::cout << tr("List of available languages for your wallet's seed:") << std::endl;
|
||||||
|
- std::cout << tr("If your display freezes, exit blind with ^C, then run again with --use-english-language-names") << std::endl;
|
||||||
|
- int ii;
|
||||||
|
- std::vector<std::string>::iterator it;
|
||||||
|
- for (it = language_list.begin(), ii = 0; it != language_list.end(); it++, ii++)
|
||||||
|
- {
|
||||||
|
- std::cout << ii << " : " << *it << std::endl;
|
||||||
|
- }
|
||||||
|
- while (language_number < 0)
|
||||||
|
- {
|
||||||
|
- language_choice = input_line(tr("Enter the number corresponding to the language of your choice: "));
|
||||||
|
- if (std::cin.eof())
|
||||||
|
- return std::string();
|
||||||
|
- try
|
||||||
|
- {
|
||||||
|
- language_number = std::stoi(language_choice);
|
||||||
|
- if (!((language_number >= 0) && (static_cast<unsigned int>(language_number) < language_list.size())))
|
||||||
|
- {
|
||||||
|
- language_number = -1;
|
||||||
|
- fail_msg_writer() << tr("invalid language choice entered. Please try again.\n");
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- catch (const std::exception &e)
|
||||||
|
- {
|
||||||
|
- fail_msg_writer() << tr("invalid language choice entered. Please try again.\n");
|
||||||
|
- }
|
||||||
|
- }
|
||||||
|
- return language_list[language_number];
|
||||||
|
+ return language_list[1];
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
boost::optional<tools::password_container> simple_wallet::get_and_verify_password() const
|
||||||
|
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
|
||||||
|
index 1bb9f52..c9fdecc 100755
|
||||||
|
--- a/src/wallet/wallet2.cpp
|
||||||
|
+++ b/src/wallet/wallet2.cpp
|
||||||
|
@@ -2952,6 +2952,13 @@ bool wallet2::load_keys(const std::string& keys_file_name, const epee::wipeable_
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ m_ask_password = false;
|
||||||
|
+ m_always_confirm_transfers = false;
|
||||||
|
+ m_confirm_subaddress = false;
|
||||||
|
+ m_confirm_backlog = false;
|
||||||
|
+ m_confirm_export_overwrite = false;
|
||||||
|
+ m_confirm_non_default_ring_size = true;
|
||||||
|
+
|
||||||
|
r = epee::serialization::load_t_from_binary(m_account, account_data);
|
||||||
|
if (r && m_key_on_device) {
|
||||||
|
LOG_PRINT_L0("Account on device. Initing device...");
|
||||||
|
diff --git a/src/wallet/wallet_args.cpp b/src/wallet/wallet_args.cpp
|
||||||
|
index fcd9cc0..ad0c3cc 100644
|
||||||
|
--- a/src/wallet/wallet_args.cpp
|
||||||
|
+++ b/src/wallet/wallet_args.cpp
|
||||||
|
@@ -122,7 +122,7 @@ namespace wallet_args
|
||||||
|
command_line::add_arg(desc_params, arg_max_concurrency);
|
||||||
|
command_line::add_arg(desc_params, arg_config_file);
|
||||||
|
|
||||||
|
- i18n_set_language("translations", "monero", lang);
|
||||||
|
+ i18n_set_language("translations", "monero", "en");
|
||||||
|
|
||||||
|
po::options_description desc_all;
|
||||||
|
desc_all.add(desc_general).add(desc_params);
|
||||||
|
@@ -134,7 +134,7 @@ namespace wallet_args
|
||||||
|
|
||||||
|
if (command_line::get_arg(vm, command_line::arg_help))
|
||||||
|
{
|
||||||
|
- Print(print) << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL;
|
||||||
|
+ Print(print) << "Wownero Light '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")" << ENDL;
|
||||||
|
Print(print) << wallet_args::tr("This is the command line wownero wallet. It needs to connect to a wownero\n"
|
||||||
|
"daemon to work correctly.") << ENDL;
|
||||||
|
Print(print) << wallet_args::tr("Usage:") << ENDL << " " << usage;
|
||||||
|
@@ -143,7 +143,7 @@ namespace wallet_args
|
||||||
|
}
|
||||||
|
else if (command_line::get_arg(vm, command_line::arg_version))
|
||||||
|
{
|
||||||
|
- Print(print) << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
|
||||||
|
+ Print(print) << "Wownero Light '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -190,7 +190,7 @@ namespace wallet_args
|
||||||
|
if (!command_line::is_arg_defaulted(vm, arg_max_concurrency))
|
||||||
|
tools::set_max_concurrency(command_line::get_arg(vm, arg_max_concurrency));
|
||||||
|
|
||||||
|
- Print(print) << "Wownero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
|
||||||
|
+ Print(print) << "Wownero Light '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
|
||||||
|
|
||||||
|
if (!command_line::is_arg_defaulted(vm, arg_log_level))
|
||||||
|
MINFO("Setting log level = " << command_line::get_arg(vm, arg_log_level));
|
@ -0,0 +1,113 @@
|
|||||||
|
{
|
||||||
|
"name": "wowlight",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"author": "dsc <xmrdsc@protonmail.com>",
|
||||||
|
"description": "Wownero Light Wallet",
|
||||||
|
"license": "WTFPL",
|
||||||
|
"main": "./dist/electron/main.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "node .electron-vue/build.js && electron-builder",
|
||||||
|
"build:dir": "node .electron-vue/build.js && electron-builder --dir",
|
||||||
|
"build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js",
|
||||||
|
"build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js",
|
||||||
|
"dev": "node .electron-vue/dev-runner.js",
|
||||||
|
"pack": "npm run pack:main && npm run pack:renderer",
|
||||||
|
"pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js",
|
||||||
|
"pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js",
|
||||||
|
"postinstall": ""
|
||||||
|
},
|
||||||
|
"build": {
|
||||||
|
"productName": "wowlight",
|
||||||
|
"appId": "org.wownero.wowlight",
|
||||||
|
"directories": {
|
||||||
|
"output": "build"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/electron/**/*"
|
||||||
|
],
|
||||||
|
"extraFiles": [
|
||||||
|
{
|
||||||
|
"from": "resources/linux",
|
||||||
|
"to": "Resources",
|
||||||
|
"filter": [
|
||||||
|
"**/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dmg": {
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"x": 410,
|
||||||
|
"y": 150,
|
||||||
|
"type": "link",
|
||||||
|
"path": "/Applications"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"x": 130,
|
||||||
|
"y": 150,
|
||||||
|
"type": "file"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"mac": {
|
||||||
|
"icon": "build/icons/icon.icns"
|
||||||
|
},
|
||||||
|
"win": {
|
||||||
|
"icon": "build/icons/icon.ico"
|
||||||
|
},
|
||||||
|
"linux": {
|
||||||
|
"icon": "build/icons",
|
||||||
|
"category": "Network;Utility"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"vue": "^2.3.3",
|
||||||
|
"axios": "^0.16.2",
|
||||||
|
"vue-electron": "^1.0.6",
|
||||||
|
"vue-router": "^2.5.3",
|
||||||
|
"vuex": "^3.0.1",
|
||||||
|
"opn": "^5.4.0",
|
||||||
|
"electron-context-menu": "0.10.0",
|
||||||
|
"jquery": "^3.3.1",
|
||||||
|
"app-root-dir": "1.0.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.25.0",
|
||||||
|
"babel-loader": "^7.1.1",
|
||||||
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
|
"babel-preset-env": "^1.6.0",
|
||||||
|
"babel-preset-stage-0": "^6.24.1",
|
||||||
|
"babel-register": "^6.24.1",
|
||||||
|
"babili-webpack-plugin": "^0.1.2",
|
||||||
|
"cfonts": "^1.1.3",
|
||||||
|
"chalk": "^2.1.0",
|
||||||
|
"copy-webpack-plugin": "^4.0.1",
|
||||||
|
"cross-env": "^5.0.5",
|
||||||
|
"css-loader": "^0.28.4",
|
||||||
|
"del": "^3.0.0",
|
||||||
|
"devtron": "^1.4.0",
|
||||||
|
"electron": "^1.7.5",
|
||||||
|
"electron-builder": "^19.19.1",
|
||||||
|
"electron-debug": "^1.4.0",
|
||||||
|
"electron-devtools-installer": "^2.2.0",
|
||||||
|
"electron-store": "^2.0.0",
|
||||||
|
"electron-util": "^0.9.0",
|
||||||
|
"extract-text-webpack-plugin": "^3.0.0",
|
||||||
|
"file-loader": "^0.11.2",
|
||||||
|
"html-webpack-plugin": "^2.30.1",
|
||||||
|
"jquery": "^3.3.1",
|
||||||
|
"multispinner": "^0.2.1",
|
||||||
|
"node-loader": "^0.6.0",
|
||||||
|
"style-loader": "^0.18.2",
|
||||||
|
"text-encoding": "^0.6.4",
|
||||||
|
"url-loader": "^0.5.9",
|
||||||
|
"vue-html-loader": "^1.2.4",
|
||||||
|
"vue-loader": "^13.0.5",
|
||||||
|
"vue-style-loader": "^3.0.1",
|
||||||
|
"vue-template-compiler": "^2.4.2",
|
||||||
|
"vuex": "^3.0.1",
|
||||||
|
"webpack": "^3.5.2",
|
||||||
|
"webpack-dev-server": "^2.7.1",
|
||||||
|
"webpack-hot-middleware": "^2.18.2"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>wowlight</title>
|
||||||
|
<script>
|
||||||
|
const {ipcRenderer} = require('electron');
|
||||||
|
// window.$ = window.jQuery = require('./assets/scripts/jquery.min.js');
|
||||||
|
window.jQuery = window.$ = require('jquery');
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<% if (htmlWebpackPlugin.options.nodeModules) { %>
|
||||||
|
<!-- Add `node_modules/` to global paths so `require` works properly in development -->
|
||||||
|
<script>
|
||||||
|
require('module').globalPaths.push('<%= htmlWebpackPlugin.options.nodeModules.replace(/\\/g, '\\\\') %>')
|
||||||
|
</script>
|
||||||
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" crossorigin="anonymous">
|
||||||
|
<% } %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div ref="app" id="app"></div>
|
||||||
|
<!-- Set `__static` path to static files in production -->
|
||||||
|
<script>
|
||||||
|
if (process.env.NODE_ENV !== 'development') window.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- webpack builds are automatically injected -->
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,22 @@
|
|||||||
|
import { join as joinPath, dirname } from 'path';
|
||||||
|
import { exec } from 'child_process';
|
||||||
|
|
||||||
|
import appRootDir from 'app-root-dir';
|
||||||
|
|
||||||
|
const IS_PROD = process.env.NODE_ENV === 'production';
|
||||||
|
console.log('Prod: ' + IS_PROD);
|
||||||
|
import getPlatform from './get-platform';
|
||||||
|
|
||||||
|
const execPath = IS_PROD ?
|
||||||
|
joinPath(dirname(appRootDir.get()), '..', 'Resources', 'bin') :
|
||||||
|
joinPath(appRootDir.get(), 'resources', getPlatform(), 'bin');
|
||||||
|
|
||||||
|
|
||||||
|
const cli_binaries = {
|
||||||
|
'linux': 'wowlight',
|
||||||
|
'mac': 'wowlight',
|
||||||
|
'win32': 'wowlight.exe'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const cliPath = `${joinPath(execPath, cli_binaries[getPlatform()])}`;
|
||||||
|
console.log('binaries.js - clipPath: ' + cliPath);
|
@ -0,0 +1,21 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
import { platform } from 'os';
|
||||||
|
|
||||||
|
export default () => {
|
||||||
|
switch (platform()) {
|
||||||
|
case 'aix':
|
||||||
|
case 'freebsd':
|
||||||
|
case 'linux':
|
||||||
|
case 'openbsd':
|
||||||
|
case 'android':
|
||||||
|
return 'linux';
|
||||||
|
case 'darwin':
|
||||||
|
case 'sunos':
|
||||||
|
return 'mac';
|
||||||
|
case 'win32':
|
||||||
|
return 'win';
|
||||||
|
case 'templeos':
|
||||||
|
return 'wow';
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* This file is used specifically and only for development. It installs
|
||||||
|
* `electron-debug` & `vue-devtools`. There shouldn't be any need to
|
||||||
|
* modify this file, but it can be used to extend your development
|
||||||
|
* environment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
|
// Set environment for development
|
||||||
|
process.env.NODE_ENV = 'development'
|
||||||
|
|
||||||
|
// Install `electron-debug` with `devtron`
|
||||||
|
require('electron-debug')({ showDevTools: true })
|
||||||
|
|
||||||
|
// Install `vue-devtools`
|
||||||
|
require('electron').app.on('ready', () => {
|
||||||
|
let installExtension = require('electron-devtools-installer')
|
||||||
|
installExtension.default(installExtension.VUEJS_DEVTOOLS)
|
||||||
|
.then(() => {})
|
||||||
|
.catch(err => {
|
||||||
|
console.log('Unable to install `vue-devtools`: \n', err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Require `main` process to boot app
|
||||||
|
require('./index')
|
@ -0,0 +1,218 @@
|
|||||||
|
import {app, BrowserWindow} from 'electron'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set `__static` path to static files in production
|
||||||
|
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
|
||||||
|
*/
|
||||||
|
if (process.env.NODE_ENV !== 'development') {
|
||||||
|
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
|
||||||
|
}
|
||||||
|
|
||||||
|
let mainWindow
|
||||||
|
|
||||||
|
const electron = require('electron');
|
||||||
|
const {ipcMain} = require('electron');
|
||||||
|
// import jQuery from 'jquery';
|
||||||
|
const wowrpc = require('./wowrpc');
|
||||||
|
|
||||||
|
const Store = require('electron-store');
|
||||||
|
const store = new Store();
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
const utils = require('electron-util');
|
||||||
|
utils.enforceMacOSAppLocation();
|
||||||
|
|
||||||
|
let homedir = (process.platform === 'win32') ? process.env.HOMEPATH : process.env.HOME;
|
||||||
|
let wowdir = `${homedir}/Wownero`;
|
||||||
|
|
||||||
|
if (!fs.existsSync(wowdir)){
|
||||||
|
console.log(`${wowdir} created`);
|
||||||
|
fs.mkdirSync(wowdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
let wallet = new wowrpc.WowRpc(wowdir);
|
||||||
|
|
||||||
|
console.log(`getWalletDir(): ${wowdir}`);
|
||||||
|
|
||||||
|
const Menu = electron.Menu;
|
||||||
|
const winURL = process.env.NODE_ENV === 'development' ? `http://localhost:9080` : `file://${__dirname}/index.html`
|
||||||
|
import { cliPath } from './binaries';
|
||||||
|
|
||||||
|
console.log(cliPath);
|
||||||
|
|
||||||
|
function createWindow() {
|
||||||
|
mainWindow = new BrowserWindow({
|
||||||
|
height: 550,
|
||||||
|
useContentSize: true,
|
||||||
|
width: 950
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.setMenu(null);
|
||||||
|
mainWindow.setResizable(false);
|
||||||
|
mainWindow.loadURL(winURL);
|
||||||
|
// mainWindow.webContents.openDevTools();
|
||||||
|
mainWindow.webContents.on("devtools-opened", () => {
|
||||||
|
mainWindow.webContents.closeDevTools();
|
||||||
|
});
|
||||||
|
|
||||||
|
mainWindow.on('closed', () => {
|
||||||
|
mainWindow = null;
|
||||||
|
console.log('lat0rz');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.on('ready', createWindow)
|
||||||
|
|
||||||
|
app.on('window-all-closed', app.quit);
|
||||||
|
app.on('before-quit', () => {
|
||||||
|
if(wallet._state !== 0){
|
||||||
|
wallet.kill();
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.removeAllListeners('close');
|
||||||
|
mainWindow.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('window-all-closed', () => {
|
||||||
|
if (process.platform !== 'darwin') {
|
||||||
|
app.quit()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.on('activate', () => {
|
||||||
|
if (mainWindow === null) {
|
||||||
|
createWindow()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('ping', (event, data) => {
|
||||||
|
console.log("received ping!");
|
||||||
|
event.sender.send('pong', Math.random());
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('rpc_get_wowdir', (event, data) => {
|
||||||
|
console.log('RPC_GET_WOWDIR');
|
||||||
|
event.sender.send('rpc_get_wowdir', wowdir);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('rpc_create_wallet', (event, data) => {
|
||||||
|
console.log('creating wallet!');
|
||||||
|
wallet.onCreateWalletFinished = function(data){
|
||||||
|
mainWindow.webContents.send('rpc_wallet_created' , data);
|
||||||
|
}
|
||||||
|
wallet.createWallet(wowdir, data.name, data.password);
|
||||||
|
event.sender.send('rpc_wallet_creating');
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('rpc_commit_wallet', (event, data) => {
|
||||||
|
console.log('commit wallet!');
|
||||||
|
console.log(data);
|
||||||
|
|
||||||
|
wallet.commitWallet(data.name);
|
||||||
|
event.sender.send('rpc_wallet_committed');
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('rate_usd_wow', (event, data) => {
|
||||||
|
console.log(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('rpc_send_monies', (event, data) => {
|
||||||
|
if(wallet._state <= 2){
|
||||||
|
event.sender.send('rpc_monies_sent_error', {'message': `wallet not ready (${wallet._state})`});
|
||||||
|
} else {
|
||||||
|
wallet.sendMonies(data.address, data.amount);
|
||||||
|
event.sender.send('rpc_sending_monies');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function resetWallet(){
|
||||||
|
if(wallet._state !== 0) {
|
||||||
|
wallet.kill();
|
||||||
|
wallet.onWalletOpened = null
|
||||||
|
wallet.onWalletBalanceChanged = null;
|
||||||
|
wallet.onWalletTxsChanged = null;
|
||||||
|
wallet.onTransactionCompleted = null;
|
||||||
|
wallet.onHeightRefresh = null;
|
||||||
|
wallet.onStateChanged = null;
|
||||||
|
wallet._setState(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet = new wowrpc.WowRpc(wowdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
ipcMain.on('rpc_close_wallet', (event) => {
|
||||||
|
resetWallet();
|
||||||
|
event.sender.send('rpc_wallet_closed');
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('rpc_kill_wallet', (event) => {
|
||||||
|
wallet.kill();
|
||||||
|
resetWallet();
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcMain.on('rpc_open_wallet', (event, data) => {
|
||||||
|
wallet.onWalletOpened = function(data){
|
||||||
|
event.sender.send('rpc_wallet_opened', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.onWalletBalanceChanged = function(data){
|
||||||
|
event.sender.send('rpc_balance_changed', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.onWalletBalanceUnlockedChanged = function(data){
|
||||||
|
event.sender.send('rpc_unlocked_changed', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.onWalletTxsChanged = function(data){
|
||||||
|
event.sender.send('rpc_txs_changed', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.onTransactionCompleted = function(data){
|
||||||
|
event.sender.send('rpc_monies_sent', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.onHeightRefresh = function(data){
|
||||||
|
console.log(`Height refresh: ${data.from} ${data.to}`);
|
||||||
|
event.sender.send('rpc_height_refreshed', {'from': data.from, 'to': data.to});
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.onStateChanged = function(data){
|
||||||
|
event.sender.send('rpc_state_changed', {'state': data});
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.onError = function(msg){
|
||||||
|
console.log(`error, killing wallet: ${msg}`);
|
||||||
|
wallet.kill();
|
||||||
|
resetWallet();
|
||||||
|
|
||||||
|
mainWindow.webContents.send('rpc_dialog_native', {
|
||||||
|
type: 'error',
|
||||||
|
title: 'Wallet error',
|
||||||
|
buttons: ['OK'],
|
||||||
|
message: `WOW!\n\n${msg}\n\nABORT ABORT ABORT! AGHGHGHGGHGHGHGHGH!!!`
|
||||||
|
});
|
||||||
|
mainWindow.webContents.send('rpc_wallet_closed');
|
||||||
|
}
|
||||||
|
|
||||||
|
wallet.connect(data.path, data.password);
|
||||||
|
event.sender.send('rpc_wallet_opening');
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto Updater
|
||||||
|
*
|
||||||
|
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-electron-builder.html#auto-updating
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
import { autoUpdater } from 'electron-updater'
|
||||||
|
|
||||||
|
autoUpdater.on('update-downloaded', () => {
|
||||||
|
autoUpdater.quitAndInstall()
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('ready', () => {
|
||||||
|
if (process.env.NODE_ENV === 'production') autoUpdater.checkForUpdates()
|
||||||
|
})
|
||||||
|
*/
|
@ -0,0 +1,9 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
class WowSettings{
|
||||||
|
constructor(){
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,515 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const os = require('os');
|
||||||
|
const path = require('path');
|
||||||
|
let childProcess = require('child_process');
|
||||||
|
let textEncoding = require('text-encoding');
|
||||||
|
let TextDecoder = textEncoding.TextDecoder;
|
||||||
|
import { cliPath } from './binaries';
|
||||||
|
|
||||||
|
export class WowRpc {
|
||||||
|
// ps -ef | grep defunct | grep -v grep | cut -b8-20 | xargs kill -9
|
||||||
|
constructor(wowdir, cli_path) {
|
||||||
|
this._wowdir = wowdir;
|
||||||
|
this._cli_process = null;
|
||||||
|
this._cli_log_path = path.join(os.tmpdir(), 'wowlight-wallet.log');
|
||||||
|
if(!cli_path) {
|
||||||
|
this._cli_path = cliPath;
|
||||||
|
} else {
|
||||||
|
this._cli_path = cli_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('WowRPC bin path: ' + this._cli_path);
|
||||||
|
|
||||||
|
this._wallet_path = '';
|
||||||
|
this._cli_wallet_password = '';
|
||||||
|
this._cli_wallet_address = null;
|
||||||
|
this._cli_wallet_selected_account = null;
|
||||||
|
this._cli_balance_unlocked = null;
|
||||||
|
this._cli_balance = null;
|
||||||
|
this._cli_txs = [];
|
||||||
|
this._buffer = "";
|
||||||
|
this._sending = false;
|
||||||
|
|
||||||
|
// this will hold the newly created wallet details: address, view_key, seed, password
|
||||||
|
this._create_wallet = {};
|
||||||
|
this._create_wallet_tmp_path = path.join(os.tmpdir(), 'wowtmp');
|
||||||
|
|
||||||
|
this._cli_args_default = [
|
||||||
|
'--use-english-language-names',
|
||||||
|
'--log-file',
|
||||||
|
this._cli_log_path
|
||||||
|
]
|
||||||
|
this._cli_args_create_wallet = [
|
||||||
|
'--generate-new-wallet',
|
||||||
|
this._create_wallet_tmp_path
|
||||||
|
]
|
||||||
|
this._cli_args_connect = [
|
||||||
|
'--daemon-address',
|
||||||
|
'node.wowne.ro:34568'
|
||||||
|
];
|
||||||
|
// '--restore-deterministic-wallet' recover from seed
|
||||||
|
|
||||||
|
// lil' state machine
|
||||||
|
// 0: not spawned
|
||||||
|
// 1: spawned - not authed
|
||||||
|
// 2: spawned - authed, not refreshed
|
||||||
|
// 3: spawned - authed/refreshed (shows prompt)
|
||||||
|
this._states = {
|
||||||
|
'cw': 'create wallet',
|
||||||
|
0: 'not spawned',
|
||||||
|
1: 'spawned - not authed',
|
||||||
|
2: 'spawned - authed',
|
||||||
|
3: 'spawned - starting refresh',
|
||||||
|
4: 'spawned - ended refresh',
|
||||||
|
5: 'spawned - showing prompt'
|
||||||
|
};
|
||||||
|
this._state = 0;
|
||||||
|
this._checkMemPoolTimeout = 10000
|
||||||
|
this.shown_transfers = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
commitWallet(wallet_name) {
|
||||||
|
// moves `/tmp/tmpwallet to destination`
|
||||||
|
console.log(`moving into: ${this._wowdir}/${wallet_name}`);
|
||||||
|
let cmd = process.platform === 'win32' ? 'move' : 'mv';
|
||||||
|
|
||||||
|
let dest_path = path.join(this._wowdir, wallet_name);
|
||||||
|
console.log(dest_path);
|
||||||
|
console.log(`${cmd} "${this._create_wallet_tmp_path}" "${dest_path}"`);
|
||||||
|
|
||||||
|
let cmd_wcache = `${cmd} "${this._create_wallet_tmp_path}" "${dest_path}"`;
|
||||||
|
let cmd_wkeys = `${cmd} "${this._create_wallet_tmp_path}.keys" "${dest_path}.keys"`;
|
||||||
|
|
||||||
|
console.log(`[CMD] ${cmd_wcache}`);
|
||||||
|
console.log(`[CMD] ${cmd_wkeys}`);
|
||||||
|
let wow = childProcess.execSync(cmd_wcache);
|
||||||
|
let wow2 = childProcess.execSync(cmd_wkeys);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_checkMemPool(){
|
||||||
|
if(this._state === 5){
|
||||||
|
this._sendCmd('show_transfers');
|
||||||
|
this._sendCmd('balance');
|
||||||
|
setTimeout(this._checkMemPool.bind(this), this._checkMemPoolTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_sendPassword(){
|
||||||
|
this.log('sending pass');
|
||||||
|
this._cli_process.stdin.write(`${this._cli_wallet_password}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sendCmd(cmd){
|
||||||
|
if(this._sending && cmd === 'show_transfers') {
|
||||||
|
// skip `show_transfers` command when making a transaction
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cmd === 'show_transfers') {
|
||||||
|
this.shown_transfers = true;
|
||||||
|
|
||||||
|
if(this._state !== 5){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log(`Sending cmd "${cmd}"`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
this._cli_process.stdin.write(`${cmd}\n`);
|
||||||
|
} catch(err) {
|
||||||
|
console.log(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cmd.startsWith('set')){
|
||||||
|
this._sendPassword();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_stdout(data){
|
||||||
|
// detect incoming transaction
|
||||||
|
let re_incoming_tx = /Height \d+, txid \<([a-zA-Z0-9]+)\>, ([0-9]+.[0-9]+), idx/g;
|
||||||
|
if(data.match(re_incoming_tx)){
|
||||||
|
let matches;
|
||||||
|
while ((matches = re_incoming_tx.exec(data)) !== null) {
|
||||||
|
this._paymentReceived(matches[1], matches[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this._state === 5 && data.match(/Error: invalid password/)){
|
||||||
|
this._sendCmd(this._cli_wallet_password);
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect show_transfers output
|
||||||
|
let re_transfers_in = /([0-9]+|pool|pending)[ ]+(in|out)[ ]+(.+?(?= ))[ ]+([0-9]+.[0-9]+)[ ]+([a-zA-Z0-9]+)/g;
|
||||||
|
if(this._state === 5 && data.match(re_transfers_in)){
|
||||||
|
let matches;
|
||||||
|
let pushed = 0;
|
||||||
|
while ((matches = re_transfers_in.exec(data)) !== null) {
|
||||||
|
let blockheight = matches[1];
|
||||||
|
if(WowRpc.isNumeric(blockheight)){
|
||||||
|
blockheight = parseInt(blockheight);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tx = {
|
||||||
|
blockheight: blockheight,
|
||||||
|
in: matches[2] === 'in' ? 'in' : 'out',
|
||||||
|
date: matches[3],
|
||||||
|
amount: matches[4],
|
||||||
|
id: matches[5]
|
||||||
|
};
|
||||||
|
|
||||||
|
if(this.getTxId(tx.id) === false){
|
||||||
|
this._cli_txs.push(tx);
|
||||||
|
pushed += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(pushed > 0){
|
||||||
|
this.log(`discovered ${pushed} tx's`);
|
||||||
|
this.wowCall(this.onWalletTxsChanged, this._cli_txs);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect cli startup
|
||||||
|
if(data.match(/This is the command line wownero wallet./)){
|
||||||
|
this._setState(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect successful transfer
|
||||||
|
if(data.match(/Transaction successfully submitted/)){
|
||||||
|
this._sending = false;
|
||||||
|
this.onTransactionCompleted();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.match(/Opened wallet: W/)){
|
||||||
|
this._cli_wallet_address = data.substring(15, data.indexOf('\n'));
|
||||||
|
this.log(`Wallet: ${this._cli_wallet_address}`);
|
||||||
|
this._setState(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(data === `Logging to ${this._cli_log_path}\n`){
|
||||||
|
// this._sendPassword();
|
||||||
|
// }
|
||||||
|
|
||||||
|
if(data.match(/Starting refresh.../)){
|
||||||
|
this._setState(3);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.match(/Error: /)){
|
||||||
|
let re_error = /Error: (.*)/g;
|
||||||
|
let re_error_offline_daemon = /wallet failed to connect to daemon: (.*):(\d+)./g;
|
||||||
|
|
||||||
|
console.log(`||${data}||`);
|
||||||
|
|
||||||
|
let re_error_offline_daemon_matched = re_error_offline_daemon.exec(data);
|
||||||
|
if(re_error_offline_daemon_matched){
|
||||||
|
let msg = `Remote node '${re_error_offline_daemon_matched[1]}:${re_error_offline_daemon_matched[2]}' offline, please use another.`;
|
||||||
|
this.onError(msg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let re_error_matched = re_error.exec(data);
|
||||||
|
if(re_error_matched){
|
||||||
|
this.onError(re_error_matched[1]);
|
||||||
|
} else {
|
||||||
|
this.onError("Unknown error occurred");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(data.match(/Refresh done, blocks received:/)){
|
||||||
|
this._setState(4);
|
||||||
|
this.onWalletOpened({
|
||||||
|
'wallet_path': this._wallet_path,
|
||||||
|
'address': this._cli_wallet_address
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let currently_selected = data.match(/Currently selected account: \[([0-9])\]/);
|
||||||
|
if(currently_selected){
|
||||||
|
this._cli_wallet_selected_account = parseInt(currently_selected[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let balance = data.match('Balance: ([0-9]+.[0-9]+)');
|
||||||
|
if(balance){
|
||||||
|
this._setBalance(balance[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let balance_unlocked = data.match('unlocked balance: ([0-9]+.[0-9]+)');
|
||||||
|
if(balance_unlocked) {
|
||||||
|
this._setBalanceUnlocked(balance_unlocked[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// detect output from command `show_transfers`
|
||||||
|
if(data.match(/\[wallet [a-zA-Z0-9]+\]:/)){
|
||||||
|
this._setState(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
let re_height_refresh = /Height (\d+) \/ (\d+)/g;
|
||||||
|
let re_height_refresh_data = re_height_refresh.exec(data);
|
||||||
|
if(re_height_refresh_data){
|
||||||
|
let from = re_height_refresh_data[1];
|
||||||
|
let to = re_height_refresh_data[2];
|
||||||
|
this.wowCall(this.onHeightRefresh, {'from': from, 'to': to});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_parse_stdout_create_wallet(data){
|
||||||
|
this._buffer += data;
|
||||||
|
|
||||||
|
if(data === `Logging to ${this._cli_log_path}\n`){
|
||||||
|
this._cli_process.stdin.write(`wow\n`);
|
||||||
|
this._cli_process.stdin.write(`wow\n`); // ?? :D
|
||||||
|
}
|
||||||
|
|
||||||
|
// if(data.match(/List of available languages for your wallet's seed:/)){
|
||||||
|
// this._cli_process.stdin.write(`1\n`);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if(data.match(/Error: invalid language choice entered./)){
|
||||||
|
// this._cli_process.stdin.write(`1\n`);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if(data.match(/Background refresh thread started/)){
|
||||||
|
let re_addy = /Generated new wallet: (W[o|W][a-zA-Z0-9]{95})/
|
||||||
|
let re_addy_match = this._buffer.match(re_addy);
|
||||||
|
if(re_addy_match){
|
||||||
|
this._create_wallet['address'] = re_addy_match[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
let re_view_key = /View key: ([0-9a-fA-F]+)\n/
|
||||||
|
let re_view_key_match = this._buffer.match(re_view_key);
|
||||||
|
if(re_view_key_match){
|
||||||
|
this._create_wallet['view_key'] = re_view_key_match[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
let re_seed = /NOTE: the following 25 words can be used to recover access to your wallet. Write them down and store them somewhere safe and secure. Please do not store them in your email or on file storage services outside of your immediate control.\n\n(.*)\n(.*)\n(.*)\n\*\*\*\*/;
|
||||||
|
let re_seed_match = this._buffer.match(re_seed);
|
||||||
|
if(re_seed_match){
|
||||||
|
let seed = `${re_seed_match[1]} ${re_seed_match[2]} ${re_seed_match[3]}`;
|
||||||
|
if(seed.split(' ').length !== 25){
|
||||||
|
this.onCreateWalletFinished("could not get seed; invalid num words");
|
||||||
|
}
|
||||||
|
|
||||||
|
this._create_wallet['seed'] = seed;
|
||||||
|
this.kill();
|
||||||
|
this.onCreateWalletFinished(this._create_wallet);
|
||||||
|
} else {
|
||||||
|
this.kill();
|
||||||
|
this.onCreateWalletFinished("could not get seed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createWallet(wowdir, name, password){
|
||||||
|
try { fs.unlinkSync(`${this._create_wallet_tmp_path}`); }
|
||||||
|
catch(err) { }
|
||||||
|
try { fs.unlinkSync(`${this._create_wallet_tmp_path}.keys`); }
|
||||||
|
catch(err) { }
|
||||||
|
|
||||||
|
let wowdir_name = path.join(wowdir, name);
|
||||||
|
if(fs.existsSync(`${wowdir_name}`) || fs.existsSync(`${wowdir_name}.keys`)){
|
||||||
|
this.onCreateWalletFinished(`Wallet already exists: ${wowdir_name}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let args = this._cli_args_default.concat(this._cli_args_create_wallet);
|
||||||
|
args.push('--password');
|
||||||
|
if(!password) {
|
||||||
|
args.push('');
|
||||||
|
} else {
|
||||||
|
args.push(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._setState('cw');
|
||||||
|
console.log('FINAL ARGS:', args);
|
||||||
|
this._cli_process = childProcess.spawn(this._cli_path, args);
|
||||||
|
|
||||||
|
this._create_wallet['name'] = name;
|
||||||
|
this._create_wallet['password'] = password;
|
||||||
|
|
||||||
|
this._cli_process.stdout.on('data', function(data) {
|
||||||
|
data = new TextDecoder("utf-8").decode(data);
|
||||||
|
console.log("[cli] " + data);
|
||||||
|
this._parse_stdout_create_wallet(data);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
this._cli_process.stdout.on('end', function(data) {
|
||||||
|
this._buffer = "";
|
||||||
|
console.log('PROCESS ENDED!')
|
||||||
|
});
|
||||||
|
|
||||||
|
this._cli_process.on('exit', function(code) {
|
||||||
|
this._buffer = "";
|
||||||
|
if (code !== 0) {
|
||||||
|
console.log('Failed: ' + code)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMonies(address, amount){
|
||||||
|
let cmd = `transfer ${address} ${amount}`;
|
||||||
|
console.log(cmd);
|
||||||
|
this._sending = true;
|
||||||
|
this._sendCmd(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
connect(wallet_path, wallet_password){
|
||||||
|
this._wallet_path = wallet_path;
|
||||||
|
this._cli_wallet_password = wallet_password;
|
||||||
|
|
||||||
|
let cli_args = [];
|
||||||
|
cli_args = cli_args.concat(this._cli_args_connect);
|
||||||
|
cli_args = cli_args.concat(this._cli_args_default);
|
||||||
|
cli_args.push('--wallet-file');
|
||||||
|
cli_args.push(wallet_path);
|
||||||
|
cli_args.push('--password');
|
||||||
|
cli_args.push(this._cli_wallet_password);
|
||||||
|
|
||||||
|
console.log('FINAL ARGS:', cli_args);
|
||||||
|
|
||||||
|
this._cli_process = childProcess.spawn(this._cli_path, cli_args);
|
||||||
|
|
||||||
|
this._cli_process.stdout.on('data', function(data) {
|
||||||
|
data = new TextDecoder("utf-8").decode(data);
|
||||||
|
console.log("[cli] " + data);
|
||||||
|
this._parse_stdout(data);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
this._cli_process.stdout.on('end', function(data) {
|
||||||
|
this._buffer = "";
|
||||||
|
console.log('PROCESS ENDED!')
|
||||||
|
});
|
||||||
|
|
||||||
|
this._cli_process.on("error", function(e) { console.log(e); });
|
||||||
|
this._cli_process.on('exit', function(code) {
|
||||||
|
this._buffer = "";
|
||||||
|
if (code !== 0) {
|
||||||
|
console.log('Failed: ' + code)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
exit(){
|
||||||
|
this._state = 0;
|
||||||
|
this._sendCmd('exit'); // seeya
|
||||||
|
this.log(`Wallet closed: ${this._cli_wallet_address}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
kill(){
|
||||||
|
console.log('Wallet kill');
|
||||||
|
this._buffer = "";
|
||||||
|
this._state = 0;
|
||||||
|
|
||||||
|
if(this._cli_process) {
|
||||||
|
this._cli_process.stdout.pause();
|
||||||
|
this._cli_process.stdin.pause();
|
||||||
|
|
||||||
|
this._cli_process.kill('SIGKILL'); // F
|
||||||
|
this.log(`Wallet closed: ${this._cli_wallet_address}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_paymentReceived(tx_id, amount){
|
||||||
|
this.log(`Incoming tx: ${tx_id}, ${amount}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setBalance(balance){
|
||||||
|
this.log(`New balance: ${balance}`);
|
||||||
|
this._cli_balance = parseFloat(balance);
|
||||||
|
|
||||||
|
this.wowCall(this.onWalletBalanceChanged, this._cli_balance);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setBalanceUnlocked(balance){
|
||||||
|
this.log(`New balance unlocked: ${balance}`);
|
||||||
|
this._cli_balance_unlocked = parseFloat(balance);
|
||||||
|
|
||||||
|
this.wowCall(this.onWalletBalanceUnlockedChanged, this._cli_balance_unlocked);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setState(state){
|
||||||
|
if(state === this._state) return;
|
||||||
|
|
||||||
|
this.log(`New state: ${this._states[state]}`);
|
||||||
|
this._state = state;
|
||||||
|
|
||||||
|
if(state === 5){
|
||||||
|
// connect check mempool loop
|
||||||
|
// this._sendCmd('set ask-password 0');
|
||||||
|
this._checkMemPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.onStateChanged(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTxId(txid){
|
||||||
|
let found = false;
|
||||||
|
this._cli_txs.forEach(function(obj){
|
||||||
|
if(obj.id === txid){
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
log(msg){
|
||||||
|
console.log('\x1b[36m%s\x1b[0m', msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
wowCall(fn, data){
|
||||||
|
// ¯\_(ツ)_/¯
|
||||||
|
if(fn != null){
|
||||||
|
fn(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletOpened(data){
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onCreateWalletFinished(){
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletAddressChanged(){
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletSelectedAccountChanged() {
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onWalletBalanceUnlockedChanged() {
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
onWalletBalanceChanged() {
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
onWalletTxsChanged(data) {
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onTransactionCompleted(){
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onHeightRefresh(data){
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onError(msg){
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
onStateChanged(state){
|
||||||
|
// overloaded
|
||||||
|
}
|
||||||
|
|
||||||
|
static isNumeric(value) {
|
||||||
|
return /^\d+$/.test(value);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,242 @@
|
|||||||
|
<template>
|
||||||
|
<div id="app" class="container nopadding nomargin">
|
||||||
|
<router-view></router-view>
|
||||||
|
|
||||||
|
<transition name="fade">
|
||||||
|
<div class="loading" v-if='hasMessage()'>
|
||||||
|
<div class="box">
|
||||||
|
<img id="logo" :src="loading_img">
|
||||||
|
<div class="text">
|
||||||
|
<h5 style="margin-bottom: 4px;">
|
||||||
|
<div class="dots" :style="`background-image: url(${path('loading.gif')})`"></div>
|
||||||
|
{{$store.state.message_box.title}}
|
||||||
|
</h5>
|
||||||
|
<p style="font-size:14px;">
|
||||||
|
{{$store.state.message_box.message}}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
|
||||||
|
<transition name="fade">
|
||||||
|
<div class="password" v-if='showPassword()'>
|
||||||
|
<div class="box">
|
||||||
|
<div class="text">
|
||||||
|
<h5 style="margin-bottom: 8px;font-size:18px;">
|
||||||
|
<span class="message">{{$store.state.password_box.message}}</span>
|
||||||
|
</h5>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-9" style="padding-right: 0;">
|
||||||
|
<input type="password" id="password" class="form-control" placeholder="..." required="" autofocus autocomplete="off" style="z-index:666;">
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">
|
||||||
|
<button id="x_btn" v-on:click="submitPassword" type="button" class="btn btn-success">
|
||||||
|
<!-- fa fa-refresh fa-spin -->
|
||||||
|
<i class="fa fa-folder-open" aria-hidden="true"></i>
|
||||||
|
Open
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'wowlight',
|
||||||
|
computed: {
|
||||||
|
height_from() {
|
||||||
|
return this.$store.getters.height_from;
|
||||||
|
},
|
||||||
|
height_to() {
|
||||||
|
return this.$store.getters.height_to;
|
||||||
|
},
|
||||||
|
walletPath(){
|
||||||
|
return this.$store.state.wallet_path;
|
||||||
|
},
|
||||||
|
walletPassword(){
|
||||||
|
return this.$store.state.wallet_password;
|
||||||
|
},
|
||||||
|
wallet(){
|
||||||
|
return this.$store.state.wallet;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
'background_pos': -200,
|
||||||
|
'loading_img': '',
|
||||||
|
'message_box_images': [],
|
||||||
|
'messages': [
|
||||||
|
"This could take a while. Or not. Who knows? It might even give you an error!",
|
||||||
|
"Two days from now, tomorrow will be yesterday.",
|
||||||
|
"You will soon have an out of money experience.",
|
||||||
|
"Two can live as cheaply as one, for half as long.",
|
||||||
|
"Hard work pay off in future. Laziness pay off now.",
|
||||||
|
"The crypto apocalypse is near, might as well have dessert.",
|
||||||
|
"This coin is no good. Try another.",
|
||||||
|
"Of all the shitcoins, you picked WOW. Congratulations!",
|
||||||
|
"WOW is going nowhere, but at least the path is interesting.",
|
||||||
|
"Indecision is key to flexibility.",
|
||||||
|
"A day without sunshine is like night.",
|
||||||
|
"The fortune you seek is in another wallet.",
|
||||||
|
"You have kleptomania. Take some WOW for it.",
|
||||||
|
"perl5 is just syntax; CPAN is the language",
|
||||||
|
"This software sucks. Why are you executing random crap from the internet?",
|
||||||
|
"Linux sucks.",
|
||||||
|
"Windows sucks.",
|
||||||
|
"OSX sucks.",
|
||||||
|
"TempleOS ftw.",
|
||||||
|
"Perl sucks.",
|
||||||
|
"garyzeasshole sucks.",
|
||||||
|
'My hobby is \'collecting magic internet money\'.',
|
||||||
|
'Hacking Roger Ver.',
|
||||||
|
'Hacking Statue of liberty.',
|
||||||
|
'Monero is better. You should use it.',
|
||||||
|
'Hacking Area 51.',
|
||||||
|
'Hacking the Illuminati.',
|
||||||
|
'Hacking everyone.',
|
||||||
|
'PRIVMSG garyzeasshole A/S/L?\\r\\n',
|
||||||
|
'Hacking all banks.',
|
||||||
|
'Be your own bank. lol.',
|
||||||
|
'Hacking fluffypony.',
|
||||||
|
'Making WOW great again.',
|
||||||
|
'Ordering Kebab.',
|
||||||
|
'Ordering Pizza.',
|
||||||
|
'SELECT * INTO OUTFILE \'/tmp/kek.dump\' FROM users; DROP TABLE clients; #cunts',
|
||||||
|
'SELECT * FROM Users WHERE UserId = 105 OR 1=1; ',
|
||||||
|
'¯\\_(ツ)_/¯',
|
||||||
|
'Shorting MoneroV.',
|
||||||
|
'Losing private keys.',
|
||||||
|
'Shorting Verge.',
|
||||||
|
'Boating accidents.',
|
||||||
|
'Forking Wownero.',
|
||||||
|
'Stealing wowbux funds.',
|
||||||
|
'Spamming bitcointalk.org.',
|
||||||
|
'Shilling wownero on reddit.',
|
||||||
|
'Spambot attacking freenode.',
|
||||||
|
'Hacking jwintern.',
|
||||||
|
'Hacking dsc.',
|
||||||
|
'Stealing WFS funds.',
|
||||||
|
'Trolling Perl community.',
|
||||||
|
'Don\'t you dare spending any WOW today.',
|
||||||
|
'No Doubt - Don\'t Speak'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
nudgeBg() {
|
||||||
|
//jQuery('#wrapper').css('background-position-y', '-200px')
|
||||||
|
//console.log(background_pos);
|
||||||
|
},
|
||||||
|
submitPassword(){
|
||||||
|
let password = jQuery('#password').val();
|
||||||
|
this.$store.commit('addWalletPassword', password);
|
||||||
|
console.log(this.walletPath);
|
||||||
|
console.log(this.walletPassword);
|
||||||
|
|
||||||
|
this.$store.commit('showPassword', {
|
||||||
|
'message': ''
|
||||||
|
});
|
||||||
|
|
||||||
|
ipcRenderer.send('rpc_open_wallet', {
|
||||||
|
path: this.walletPath, password: this.walletPassword
|
||||||
|
});
|
||||||
|
},
|
||||||
|
entryFromArr(arr){
|
||||||
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
|
},
|
||||||
|
showPassword() {
|
||||||
|
return this.$store.state.password_box.message !== "";
|
||||||
|
},
|
||||||
|
hasMessage() {
|
||||||
|
if(this.$store.state.message_box.title !== "") {
|
||||||
|
let url = this.entryFromArr(this.message_box_images);
|
||||||
|
let url_spl = url.split('.');
|
||||||
|
this.loading_img = this.path(url);
|
||||||
|
|
||||||
|
if(this.$store.state.message_box.message === "") {
|
||||||
|
let message = this.entryFromArr(this.messages);
|
||||||
|
let a = {
|
||||||
|
'title': this.$store.state.message_box.title,
|
||||||
|
'message': message
|
||||||
|
}
|
||||||
|
|
||||||
|
this.$store.commit('showMessage', a);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
path (icon) {
|
||||||
|
// vuejs+webpack sux
|
||||||
|
return require(`./assets/loading/${icon}`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted () {
|
||||||
|
Array.prototype.insert = function ( index, item ) {
|
||||||
|
this.splice( index, 0, item );
|
||||||
|
};
|
||||||
|
|
||||||
|
jQuery(document).ready(function(){
|
||||||
|
jQuery('#background').animate({
|
||||||
|
'background-position-y': '-200px'
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let i = 0; i < 32; i++) {
|
||||||
|
this.message_box_images.push('l' + i + '.gif');
|
||||||
|
}
|
||||||
|
|
||||||
|
let html = jQuery('body');
|
||||||
|
let window_width = jQuery(window).width();
|
||||||
|
let window_height = jQuery(window).height();
|
||||||
|
|
||||||
|
jQuery(document).mousemove((event) => {
|
||||||
|
let offset_x = 100 - (event.pageX / window_width) * 100;
|
||||||
|
let offset_y = -40 - (event.pageY / window_height) * 100;
|
||||||
|
|
||||||
|
html.css('background-position-x', '' + (offset_x / 5) + 'px');
|
||||||
|
html.css('background-position-y', '' + (offset_y / 5) + 'px');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$electron.ipcRenderer.on('rpc_wallet_opened', (event) => {
|
||||||
|
this.$store.commit('showMessage', {
|
||||||
|
'title': '',
|
||||||
|
'message': ''
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$electron.ipcRenderer.on('rpc_dialog_native', (event, data) => {
|
||||||
|
const {dialog} = require('electron').remote;
|
||||||
|
dialog.showMessageBox(data, i => {
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
jQuery(document).keyup((e) => {
|
||||||
|
if(this.$store.state.password_box.message !== "") {
|
||||||
|
if (e.keyCode === 13) {
|
||||||
|
this.submitPassword();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.keyCode === 27) {
|
||||||
|
this.$store.commit('showPassword', {
|
||||||
|
'message': ''
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro');
|
||||||
|
@import url('~@/assets/bootstrap.min.css');
|
||||||
|
@import url('~@/assets/wow.css');
|
||||||
|
</style>
|
After Width: | Height: | Size: 959 KiB |
After Width: | Height: | Size: 89 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 2.3 KiB |
After Width: | Height: | Size: 109 KiB |
After Width: | Height: | Size: 216 KiB |
After Width: | Height: | Size: 131 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 32 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 473 KiB |
After Width: | Height: | Size: 66 KiB |
After Width: | Height: | Size: 496 KiB |
After Width: | Height: | Size: 293 KiB |
After Width: | Height: | Size: 170 KiB |
After Width: | Height: | Size: 681 KiB |
After Width: | Height: | Size: 463 KiB |
After Width: | Height: | Size: 453 KiB |
After Width: | Height: | Size: 454 KiB |
After Width: | Height: | Size: 1.6 MiB |
After Width: | Height: | Size: 423 KiB |
After Width: | Height: | Size: 265 KiB |
After Width: | Height: | Size: 510 KiB |
After Width: | Height: | Size: 448 KiB |
After Width: | Height: | Size: 228 KiB |
After Width: | Height: | Size: 311 KiB |
After Width: | Height: | Size: 1.2 MiB |
After Width: | Height: | Size: 543 KiB |
After Width: | Height: | Size: 614 KiB |
After Width: | Height: | Size: 175 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 513 KiB |
After Width: | Height: | Size: 601 KiB |
After Width: | Height: | Size: 62 KiB |
After Width: | Height: | Size: 689 KiB |
After Width: | Height: | Size: 461 KiB |
After Width: | Height: | Size: 755 KiB |
After Width: | Height: | Size: 144 KiB |
After Width: | Height: | Size: 136 KiB |
After Width: | Height: | Size: 248 KiB |
After Width: | Height: | Size: 448 KiB |
After Width: | Height: | Size: 694 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 695 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 33 KiB |
After Width: | Height: | Size: 47 KiB |
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 208 KiB |
After Width: | Height: | Size: 8.5 KiB |
After Width: | Height: | Size: 49 KiB |