-
-
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
Showing
19 changed files
with
768 additions
and
64 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
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
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
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
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,44 @@ | ||
/* | ||
Copyright © 2024 Front Matter <[email protected]> | ||
*/ | ||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/front-matter/commonmeta/ghost" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// encodeCmd represents the encode command | ||
var updateGhostAPICmd = &cobra.Command{ | ||
Use: "update-ghost-post", | ||
Short: "A brief description of your command", | ||
Long: `A longer description that spans multiple lines and likely contains examples | ||
and usage of using your command. For example: | ||
Cobra is a CLI library for Go that empowers applications. | ||
This application is a tool to generate the needed files | ||
to quickly create a Cobra application.`, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if len(args) == 0 { | ||
fmt.Println("Please provide an input") | ||
return | ||
} | ||
id := args[0] | ||
apiKey, _ := cmd.Flags().GetString("api-key") | ||
apiURL, _ := cmd.Flags().GetString("api-url") | ||
output, err := ghost.UpdateGhostPost(id, apiKey, apiURL) | ||
if err != nil { | ||
fmt.Println(err) | ||
} | ||
fmt.Println(output) | ||
}, | ||
} | ||
|
||
func init() { | ||
rootCmd.AddCommand(updateGhostAPICmd) | ||
|
||
rootCmd.PersistentFlags().StringP("api-key", "", "", "Ghost API key") | ||
rootCmd.PersistentFlags().StringP("api-url", "", "", "Ghost API URL") | ||
} |
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,106 @@ | ||
package crockford | ||
|
||
import ( | ||
"fmt" | ||
"math" | ||
"math/rand/v2" | ||
"strconv" | ||
"strings" | ||
) | ||
|
||
// Generate, encode and decode random base32 identifiers. | ||
// This encoder/decoder: | ||
// - uses Douglas Crockford Base32 encoding: https://www.crockford.com/base32.html | ||
// - allows for ISO 7064 checksum | ||
// - encodes the checksum using only characters in the base32 set | ||
// - produces string that are URI-friendly (no '=' or '/' for instance) | ||
// This is based on: https://github.com/front-matter/base32-url | ||
|
||
// NO i, l, o or u | ||
const ENCODING_CHARS = "0123456789abcdefghjkmnpqrstvwxyz" | ||
|
||
// Encode a number to a URI-friendly Douglas Crockford base32 string. | ||
// optionally split with ' -' every n characters, pad with zeros to a minimum length, | ||
// and append a checksum using modulo 97-10 (ISO 7064). | ||
func Encode(number int64, splitEvery int, length int, checksum bool) string { | ||
encoded := "" | ||
originalNumber := number | ||
if number == 0 { | ||
encoded = "0" | ||
} else { | ||
for number > 0 { | ||
remainder := number % 32 | ||
number /= 32 | ||
encoded = string(ENCODING_CHARS[remainder]) + encoded | ||
} | ||
} | ||
|
||
if checksum && length > 2 { | ||
length -= 2 | ||
} | ||
if length > 0 && len(encoded) < length { | ||
encoded = strings.Repeat("0", length-len(encoded)) + encoded | ||
} | ||
if length > 0 { | ||
encoded = encoded[:length] | ||
} | ||
|
||
if checksum { | ||
computedChecksum := 97 - ((100 * originalNumber) % 97) + 1 | ||
encoded += fmt.Sprintf("%02d", computedChecksum) | ||
} | ||
|
||
if splitEvery > 0 { | ||
var splits []string | ||
for i := 0; i < len(encoded); i += splitEvery { | ||
nn := i + splitEvery | ||
if nn > len(encoded) { | ||
nn = len(encoded) | ||
} | ||
splits = append(splits, string(encoded[i:nn])) | ||
} | ||
encoded = strings.Join(splits, "-") | ||
} | ||
|
||
return encoded | ||
} | ||
|
||
// Generate a random Cockroft base32 string. | ||
// optionally split with ' -' every n characters, pad with zeros to a minimum length, | ||
// and append a checksum using modulo 97-10 (ISO 7064). | ||
func Generate(length int, splitEvery int, checksum bool) string { | ||
if checksum && length < 3 { | ||
panic("Invalid 'length'. Must be >= 3 if checksum enabled.") | ||
} | ||
// generate a random number between 0 and 32^length | ||
n := math.Pow(float64(32), float64(length)) | ||
number := int64(rand.IntN(int(n))) | ||
str := Encode(number, splitEvery, length, checksum) | ||
return str | ||
} | ||
|
||
// Decode a URI-friendly Douglas Crockford base32 string to a number. | ||
func Decode(encoded string, checksum bool) (int64, error) { | ||
var encodedChecksum int64 | ||
number := int64(0) | ||
encoded = strings.ReplaceAll(encoded, "-", "") | ||
if checksum { | ||
encodedChecksum, _ = strconv.ParseInt(encoded[len(encoded)-2:], 10, 64) | ||
encoded = encoded[:len(encoded)-2] | ||
} | ||
for _, c := range encoded { | ||
number *= 32 | ||
pos := strings.Index(ENCODING_CHARS, string(c)) | ||
if pos == -1 { | ||
return 0, fmt.Errorf("invalid character: %s", string(c)) | ||
} | ||
number += int64(pos) | ||
} | ||
if checksum { | ||
computedChecksum := 97 - ((100 * number) % 97) + 1 | ||
if computedChecksum != encodedChecksum { | ||
return 0, fmt.Errorf("invalid checksum: %d", encodedChecksum) | ||
} | ||
} | ||
return number, nil | ||
} |
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,83 @@ | ||
package crockford_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/front-matter/commonmeta/crockford" | ||
) | ||
|
||
func TestEncode(t *testing.T) { | ||
t.Parallel() | ||
type testCase struct { | ||
input int64 | ||
splitEvery int | ||
length int | ||
checksum bool | ||
want string | ||
} | ||
testCases := []testCase{ | ||
{input: 0, want: "0", splitEvery: 0, length: 0, checksum: false}, | ||
{input: 1234, want: "16j", splitEvery: 0, length: 0, checksum: false}, | ||
{input: 1234, want: "16-j", splitEvery: 2, length: 0, checksum: false}, | ||
{input: 1234, want: "01-6j", splitEvery: 2, length: 4, checksum: false}, | ||
{input: 538751765283013, want: "f9zqn-sf065", splitEvery: 5, length: 10, checksum: false}, | ||
{input: 712266282077, want: "mqb61-x2x15", splitEvery: 5, length: 10, checksum: true}, | ||
} | ||
for _, tc := range testCases { | ||
got := crockford.Encode(tc.input, tc.splitEvery, tc.length, tc.checksum) | ||
if tc.want != got { | ||
t.Errorf("Encode(%v): want %v, got %v", | ||
tc.input, tc.want, got) | ||
} | ||
} | ||
} | ||
|
||
func TestGenerate(t *testing.T) { | ||
t.Parallel() | ||
type testCase struct { | ||
length int | ||
splitEvery int | ||
checksum bool | ||
} | ||
testCases := []testCase{ | ||
{length: 4, splitEvery: 0, checksum: false}, | ||
{length: 10, splitEvery: 5, checksum: false}, | ||
{length: 10, splitEvery: 5, checksum: true}, | ||
} | ||
for _, tc := range testCases { | ||
got := crockford.Generate(tc.length, tc.splitEvery, tc.checksum) | ||
length := tc.length | ||
if tc.splitEvery > 0 { | ||
length += tc.length/tc.splitEvery - 1 | ||
} | ||
if len(got) != length { | ||
t.Errorf("Generate(%v): want length %v, got %v", | ||
tc.length, tc.length, len(got)) | ||
} | ||
} | ||
} | ||
|
||
func TestDecode(t *testing.T) { | ||
t.Parallel() | ||
type testCase struct { | ||
input string | ||
checksum bool | ||
want int64 | ||
} | ||
testCases := []testCase{ | ||
{input: "0", want: 0, checksum: false}, | ||
{input: "16j", want: 1234, checksum: false}, | ||
{input: "16-j", want: 1234, checksum: false}, | ||
{input: "01-6j", want: 1234, checksum: false}, | ||
{input: "f9zqn-sf065", want: 538751765283013, checksum: false}, | ||
{input: "mqb61-x2x15", want: 712266282077, checksum: true}, | ||
{input: "axgv5-6aq97", want: 375301249367, checksum: true}, | ||
} | ||
for _, tc := range testCases { | ||
got, err := crockford.Decode(tc.input, tc.checksum) | ||
if tc.want != got { | ||
t.Errorf("Decode(%v): want %v, got %v, error %v", | ||
tc.input, tc.want, got, err) | ||
} | ||
} | ||
} |
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
Oops, something went wrong.