This repository has been archived by the owner on Apr 28, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 475e93d
Showing
7 changed files
with
252 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
package-lock.json | ||
src/sma | ||
build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "src/sma"] | ||
path = src/sma | ||
url = https://github.com/fiskaly/fiskaly-kassensichv-sma.git |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
The MIT License | ||
|
||
Copyright (c) 2019 fiskaly GmbH (http://fiskaly.com) | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in | ||
all copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
THE SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
{ | ||
"name": "fiskaly-kassensichv-client-js", | ||
"version": "0.0.1-alpha", | ||
"license": "MIT", | ||
"homepage": "https://fiskaly.com", | ||
"scripts": { | ||
"start": "npm run build && http-server build -o -g --cors", | ||
"build": "npm run clean && npm run build:example && npm run build:js && npm run build:wasm && npm run build:compress", | ||
"build:js": "cat src/sma/dist/com.fiskaly.kassensichv.sma-web.js src/client.js | minify > build/com.fiskaly.kassensichv.sma-web.js", | ||
"build:wasm": "cp src/sma/dist/com.fiskaly.kassensichv.sma-web.wasm build/com.fiskaly.kassensichv.sma-web.wasm", | ||
"build:example": "cp src/example.html build/", | ||
"build:compress": "gzip -k -9 build/*", | ||
"clean": "mkdir -p build && rm -f build/*", | ||
"lint": "standard --fix" | ||
}, | ||
"devDependencies": { | ||
"babel-minify": "^0.5.1", | ||
"http-server": "^0.11.1", | ||
"standard": "^14.3.1" | ||
}, | ||
"standard": { | ||
"ignore": [ | ||
"src/sma" | ||
] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
|
||
// Copyright 2019 fiskaly GmbH. All rights reserved. | ||
|
||
/* eslint-env browser */ | ||
/* globals Go, com */ | ||
|
||
(function () { | ||
const initialized = (async function () { | ||
const go = new Go() | ||
const input = fetch('com.fiskaly.kassensichv.sma-web.wasm') | ||
const { instance } = await WebAssembly.instantiateStreaming(input, go.importObject) | ||
go.run(instance) | ||
})() | ||
|
||
Object.defineProperty(window, 'com', { value: {} }) | ||
Object.defineProperty(window.com, 'fiskaly', { value: {} }) | ||
Object.defineProperty(window.com.fiskaly, 'kassensichv', { value: {} }) | ||
Object.defineProperty(window.com.fiskaly.kassensichv, 'sma', { value: { invoke } }) | ||
Object.defineProperty(window.com.fiskaly.kassensichv, 'client', { value: client }) | ||
|
||
async function invoke (method, maybeParams) { | ||
await initialized | ||
return new Promise((resolve, reject) => { | ||
const params = Array.isArray(maybeParams) | ||
? maybeParams | ||
: [maybeParams] | ||
const id = Math.floor(Date.now() + (Math.random() * 10000)) | ||
const request = { | ||
jsonrpc: '2.0', | ||
method, | ||
params, | ||
id | ||
} | ||
const requestJson = JSON.stringify(request) | ||
com.fiskaly.kassensichv.sma.doInvoke(requestJson, responseJson => { | ||
const response = JSON.parse(responseJson) | ||
const { result, error } = response | ||
if (error != null) { | ||
const { message, ...props } = error | ||
const err = Object.assign(new Error(message), props) | ||
reject(err) | ||
} else { | ||
resolve(result) | ||
} | ||
}) | ||
}) | ||
} | ||
|
||
function client ( | ||
apiKey, | ||
apiSecret, | ||
opts = { | ||
baseUrl: 'https://kassensichv.fiskaly.com/api/v0' | ||
} | ||
) { | ||
const { baseUrl } = opts | ||
const authContext = {} | ||
|
||
const fetchRaw = async ({ method = 'GET', path, query, body, headers = {} }) => { | ||
const url = baseUrl + path | ||
const fetchOpts = { method, headers } | ||
if (body != null) { | ||
fetchOpts.body = JSON.stringify(body) | ||
} | ||
const res = await fetch(url, fetchOpts) | ||
return res | ||
} | ||
|
||
const fetchToken = async (body) => { | ||
const res = await fetchRaw({ | ||
method: 'POST', | ||
path: '/auth', | ||
headers: { | ||
'content-type': 'application/json' | ||
}, | ||
body | ||
}) | ||
const result = await res.json() | ||
authContext.accessToken = result.access_token | ||
authContext.refreshToken = result.refresh_token | ||
authContext.refreshInterval = result.refresh_token_expires_in * 1000 / 10 | ||
} | ||
|
||
const auth = async () => { | ||
clearInterval(authContext.timerId) | ||
await fetchToken({ | ||
api_key: apiKey, | ||
api_secret: apiSecret | ||
}) | ||
const { refreshInterval } = authContext | ||
authContext.timerId = setInterval(() => { | ||
fetchToken({ refresh_token: authContext.refreshToken }) | ||
}, refreshInterval) | ||
} | ||
|
||
const overrideTxPath = (str) => { | ||
const [path, query] = str.split('?') | ||
const parts = [path, '/log', query && `?${query}`] | ||
return parts.filter(Boolean).join('') | ||
} | ||
|
||
const interceptTxRequest = async (options) => { | ||
const { body, path } = options | ||
const signedTx = await com.fiskaly.kassensichv.sma.invoke('sign-transaction', body) | ||
options.path = overrideTxPath(path) | ||
options.body = signedTx | ||
} | ||
|
||
const request = async (options, retry = 0) => { | ||
if (retry > 5) { | ||
throw new Error('reached maxmimum number of retries') | ||
} | ||
const { path, method } = options | ||
if (authContext.accessToken == null) { | ||
await auth() | ||
} | ||
const isPut = /put/i.test(method) | ||
const isTxPath = /^\/tss\/.+\/tx\/.+/i.test(path) | ||
if (isPut && isTxPath) { | ||
await interceptTxRequest(options) | ||
} | ||
const result = await fetchRaw({ | ||
...options, | ||
headers: { | ||
'content-type': 'application/json', | ||
authorization: `Bearer ${authContext.accessToken}` | ||
} | ||
}) | ||
const { status } = result | ||
if (status === 401) { | ||
delete authContext.accessToken | ||
return request(options, retry + 1) // retry | ||
} | ||
const body = await result.json() | ||
const headers = Object.fromEntries(result.headers.entries()) | ||
return { status, body, headers } | ||
} | ||
|
||
return request | ||
} | ||
})() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<body> | ||
<pre>Hint: open your browser console to see the magic (F12)!</pre> | ||
|
||
<script src="com.fiskaly.kassensichv.sma-web.js"></script> | ||
|
||
<script> | ||
const apiKey = 'TODO INSERT YOUR API KEY HERE' | ||
const apiSecret = 'TODO INSERT YOUR API SECRET HERE' | ||
|
||
main().catch(console.error) | ||
|
||
async function main() { | ||
const smaVersion = await com.fiskaly.kassensichv.sma.invoke('version') | ||
console.log('Checking SMA version...', smaVersion) | ||
if (/TODO/.test(apiKey) || /TODO/.test(apiSecret)) { | ||
throw new Error('Insert your apiKey and/or apiSecrets first') | ||
} | ||
const client = com.fiskaly.kassensichv.client(apiKey, apiSecret) | ||
const clientList = await client({ path: '/client' }) | ||
const firstClient = clientList.body.data[0] | ||
if (firstClient == null) { | ||
throw new Error('Create a client and TSS in the dashboard first') | ||
} | ||
const clientId = firstClient._id | ||
const tssId = firstClient.tss_id | ||
console.log('Choosing first available TSS...', tssId) | ||
console.log('Choosing first available Client...', clientId) | ||
const txId = uuidv4() | ||
const txBody = { | ||
state: 'ACTIVE', | ||
type: 'OTHER', | ||
client_id: clientId, | ||
data: { | ||
aeao: { | ||
other: {} | ||
} | ||
} | ||
} | ||
const txPath = `/tss/${tssId}/tx/${txId}` | ||
const tx = await client({ | ||
method: 'PUT', | ||
path: txPath, | ||
body: txBody | ||
}) | ||
console.log('Started Transaction...', tx.body) | ||
console.log(`See Transaction in the Dashboard: https://dashboard.fiskaly.com/kassensichv${txPath}`) | ||
} | ||
|
||
function uuidv4() { | ||
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => | ||
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16) | ||
) | ||
} | ||
</script> | ||
</body> |