Replies: 8 comments 7 replies
-
I need to create a "check-out/check-in" (or leasing) licensing for my program written with Python. Based on reading your website (very well written), I'll need to add heartbeat monitoring. Is any sample code available? I successfully used the "example-python-machine-activation" for node-based licensing during my beta testing. My clients are interested in buying some licenses for multiple users (for example, 3 licenses for 5 or more users). I'm getting stuck on how to start this process. |
Beta Was this translation helpful? Give feedback.
-
Working on Now Playing 2. It's an app for DJs who live stream. It automatically connects to your DJ equipment and adds the currently playing track to your Twitch / YouTube live stream. https://www.nowplaying2.com I honestly wish I found keygen a LOT sooner because I'm now reworking a bunch of the app to make use of it. :) |
Beta Was this translation helpful? Give feedback.
-
I'm working on an electron based app. Testing the license function. |
Beta Was this translation helpful? Give feedback.
-
I'm working on an electron app using a combination of offline license caching and verification. I'm a big typescript guy, so I'll share the helper I wrote to use axios for keygen requests but verify the responses. Hopefully this will save someone some time =] It probably still needs to do a better job of handling error conditions, but should be useful for anyone wanting to use axios to talk to keygen in node.js or electron (and hopefully that'll give enough search terms to make this findable) import axios, { AxiosRequestConfig, AxiosResponse, AxiosResponseHeaders } from "axios";
import crypto from "crypto";
// Replace this with your ed25519 public key
const EdPublicKey = 'MCow........=';
const verifyPubKey = crypto.createPublicKey({
key: Buffer.from(EdPublicKey, "base64"),
format: "der",
type: "spki",
});
/**
* Call this function instead of axios.request() in order to make a request to the keygen server
* which does not
* @param opts Axios request options
* @returns
*/
export async function keygenRequest<T>(opts: AxiosRequestConfig) {
const headers = {
...opts.headers || {},
'Accept': 'application/vnd.api+json',
'Content-Type': 'application/vnd.api+json',
'Keygen-Accept-Signature': 'algorithm="ed25519"',
}
const resp = await axios.request<string>({
...opts,
headers,
transformResponse: (data: any) => data,
});
const uriObj = new URL(opts.url);
const withoutHost = opts.url.substring(opts.url.indexOf(uriObj.pathname));
verify(resp.data, resp.headers, withoutHost, opts.method?.toLowerCase() || 'get', uriObj.host);
resp.data = JSON.parse(resp.data);
return resp as unknown as AxiosResponse<T>;
}
interface KeyGenSignature {
keyid: string;
algorithm: string;
signature: string;
headers: string[];
}
function parseParameterizedHeader(header: string) {
if (header == null) {
return null;
}
const params = header.split(/\s*,\s*/g);
const keyvalues = params.map((param) => {
const [, key, value] = param.match(/([^=]+)="([^"]+)"/i);
return [key, value];
});
return keyvalues.reduce(
(o, [k, v]) => ((o[k] = v), o),
{} as Record<string, string>
) as unknown as KeyGenSignature;
}
export function verify(body: any, headers: AxiosResponseHeaders, uri: string, method: string, host: string = 'api.keygen.sh') {
// Parse and verify the response signature
// Parse the signature header
const header = parseParameterizedHeader(headers["keygen-signature"]);
// Extract the algorithm and signature from the header
const { algorithm, signature } = header;
// Ensure signing algorithm is what we expect
if (algorithm !== "ed25519") {
throw new Error("Invalid signature algorithm");
}
// Verify integrity
const hash = crypto.createHash("sha256").update(body);
const digest = `sha-256=${hash.digest("base64")}`;
if (digest !== headers['digest']) {
throw new Error("Invalid digest");
}
// Reconstruct the signing data
const date = headers['date'];
const data = [
`(request-target): ${method} ${uri}`,
`host: ${host}`,
`date: ${date}`,
`digest: ${digest}`,
].join("\n");
// Initialize our public key
// Decode and verify the signature
const signatureBytes = Buffer.from(signature, "base64");
const dataBytes = Buffer.from(data);
const ok = crypto.verify(null, dataBytes, verifyPubKey, signatureBytes);
if (!ok) {
throw new Error("invalid signature");
}
} |
Beta Was this translation helpful? Give feedback.
-
I'm re-writing a 30 year-old, completely undocumented engineering app for Windows in C#. The legacy version was written in VB6 and relied on a klunky, manual licensing / billing / renewal system and a gigantic Excel spreadsheet. I aim to modernize it so that users can purchase and manage licenses through the business' website. |
Beta Was this translation helpful? Give feedback.
-
Hi, Hope you all are doing well I am working on a plugin which I am planning to license (feature-based subscription, online and offline, probably node-locked). Regards, |
Beta Was this translation helpful? Give feedback.
-
Hi, Hope you all are doing well I am working on a product which I am planning to license (online and offline for user-node-locked,node-locked and floating license).So I need to implement offline licensing . Regards, |
Beta Was this translation helpful? Give feedback.
-
Hi, I am working on deploying a product in docker swarm mode, and currently has keygen integration into the server end. I am currently hosting my docker images as artifacts on Keygen. Its working great, thanks to the whole team and community <3 I have hit a roadblock where i want to configure Swarmpit/swarm mode to check for docker image updates and redeployments, but cant figure out how to integrate with Keygen.sh, as its not a proper docker registery. Any help would be much appreciated. Thanks for this wholesome product. |
Beta Was this translation helpful? Give feedback.
-
I figured I'd try and kickstart some discussion by seeing what everybody is working on. Feel free to share! 😃
Beta Was this translation helpful? Give feedback.
All reactions