站点更新:2018-03-27 15:37:33

master
ehlxr 2018-03-27 15:37:33 +08:00
commit 97257044a4
19 changed files with 1152 additions and 0 deletions

6
.idea/emacs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="EmacsSettings">
<option name="emacsPath" value="/usr/bin/emacs" />
</component>
</project>

9
.idea/jwt.iml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/jwt.iml" filepath="$PROJECT_DIR$/.idea/jwt.iml" />
</modules>
</component>
</project>

53
.idea/watcherTasks.xml Normal file
View File

@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectTasksOptions">
<TaskOptions isEnabled="true">
<option name="arguments" value="fmt $FilePath$" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="go" />
<option name="immediateSync" value="false" />
<option name="name" value="go fmt" />
<option name="output" value="$FilePath$" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="$GoExecPath$" />
<option name="runOnExternalChanges" value="false" />
<option name="scopeName" value="Project Files" />
<option name="trackOnlyRoot" value="true" />
<option name="workingDir" value="" />
<envs>
<env name="GOROOT" value="$GOROOT$" />
<env name="GOPATH" value="$GOPATH$" />
<env name="PATH" value="$GoBinDirs$" />
</envs>
</TaskOptions>
<TaskOptions isEnabled="true">
<option name="arguments" value="-w $FilePath$" />
<option name="checkSyntaxErrors" value="true" />
<option name="description" />
<option name="exitCodeBehavior" value="ERROR" />
<option name="fileExtension" value="go" />
<option name="immediateSync" value="false" />
<option name="name" value="goimports" />
<option name="output" value="$FilePath$" />
<option name="outputFilters">
<array />
</option>
<option name="outputFromStdout" value="false" />
<option name="program" value="goimports" />
<option name="runOnExternalChanges" value="false" />
<option name="scopeName" value="Project Files" />
<option name="trackOnlyRoot" value="true" />
<option name="workingDir" value="" />
<envs>
<env name="GOROOT" value="$GOROOT$" />
<env name="GOPATH" value="$GOPATH$" />
<env name="PATH" value="$GoBinDirs$" />
</envs>
</TaskOptions>
</component>
</project>

302
.idea/workspace.xml Normal file
View File

@ -0,0 +1,302 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="847c5949-378a-4c01-9318-d1db88c22ef9" name="Default" comment="" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="TRACKING_ENABLED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileEditorManager">
<leaf>
<file leaf-file-name="showtoken.go" pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/token/showtoken.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="527">
<caret line="39" column="24" lean-forward="true" selection-start-line="39" selection-start-column="24" selection-end-line="39" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="token.go" pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/token/token.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="251">
<caret line="38" column="5" lean-forward="false" selection-start-line="38" selection-start-column="5" selection-end-line="38" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="GOROOT" path="/usr/local/opt/go/libexec" />
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/cmd/verify.go" />
<option value="$PROJECT_DIR$/cmd/show.go" />
<option value="$PROJECT_DIR$/token/signtoken.go" />
<option value="$PROJECT_DIR$/cmd/sign.go" />
<option value="$PROJECT_DIR$/token/token.go" />
</list>
</option>
</component>
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
<component name="JsGulpfileManager">
<detection-done>true</detection-done>
<sorting>DEFINITION_ORDER</sorting>
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="1920" />
<option name="y" value="23" />
<option name="width" value="1440" />
<option name="height" value="877" />
</component>
<component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
<showLibraryContents />
<hideEmptyPackages />
<abbreviatePackageNames />
<autoscrollToSource />
<autoscrollFromSource />
<sortByType />
<manualOrder />
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="Scratches" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="jwt" type="b2602c69:ProjectViewProjectNode" />
<item name="jwt" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="jwt" type="b2602c69:ProjectViewProjectNode" />
<item name="jwt" type="462c0819:PsiDirectoryNode" />
<item name="cmd" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="jwt" type="b2602c69:ProjectViewProjectNode" />
<item name="jwt" type="462c0819:PsiDirectoryNode" />
<item name="token" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
<pane id="Scope" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="go.sdk.automatically.set" value="true" />
<property name="settings.editor.selected.configurable" value="watcher.settings" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager">
<configuration name="go build main.go" type="GoApplicationRunConfiguration" factoryName="Go Application" temporary="true">
<module name="jwt" />
<working_directory value="$PROJECT_DIR$/" />
<go_parameters value="-i" />
<parameters value="show -t -" />
<kind value="FILE" />
<filePath value="$PROJECT_DIR$/main.go" />
<package value="github.com/ehlxr/jwt" />
<directory value="$PROJECT_DIR$/" />
</configuration>
<recent_temporary>
<list size="1">
<item index="0" class="java.lang.String" itemvalue="Go Build.go build main.go" />
</list>
</recent_temporary>
</component>
<component name="ShelveChangesManager" show_recycled="false">
<option name="remove_strategy" value="false" />
</component>
<component name="ToolWindowManager">
<frame x="1920" y="23" width="1440" height="877" extended-state="6" />
<editor active="true" />
<layout>
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32992327" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.17381974" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24964234" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Docker" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="false" content_ui="tabs" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32992327" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="-1" side_tool="true" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.39897698" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager>
<breakpoints>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/token/token.go</url>
<line>45</line>
<properties />
<option name="timeStamp" value="4" />
</line-breakpoint>
<line-breakpoint enabled="true" type="DlvLineBreakpoint">
<url>file://$PROJECT_DIR$/token/token.go</url>
<line>39</line>
<properties />
<option name="timeStamp" value="7" />
</line-breakpoint>
</breakpoints>
<option name="time" value="8" />
</breakpoint-manager>
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/main.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="247">
<caret line="13" column="20" lean-forward="false" selection-start-line="13" selection-start-column="20" selection-end-line="13" selection-end-column="20" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/cmd/root.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="317">
<caret line="47" column="18" lean-forward="true" selection-start-line="46" selection-start-column="8" selection-end-line="47" selection-end-column="18" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/cmd/show.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="129">
<caret line="39" column="22" lean-forward="true" selection-start-line="39" selection-start-column="22" selection-end-line="39" selection-end-column="22" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/util/tokenutil.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="185">
<caret line="34" column="5" lean-forward="false" selection-start-line="34" selection-start-column="5" selection-end-line="34" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../../spf13/pflag/string.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="171">
<caret line="9" column="0" lean-forward="true" selection-start-line="9" selection-start-column="0" selection-end-line="9" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../../spf13/pflag/uint64.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="95">
<caret line="5" column="5" lean-forward="false" selection-start-line="5" selection-start-column="5" selection-end-line="5" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../../spf13/pflag/duration.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="95">
<caret line="7" column="5" lean-forward="false" selection-start-line="7" selection-start-column="5" selection-end-line="7" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../../spf13/pflag/flag.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="142">
<caret line="174" column="8" lean-forward="false" selection-start-line="174" selection-start-column="8" selection-end-line="174" selection-end-column="8" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/../../spf13/pflag/flag_test.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="379">
<caret line="1072" column="14" lean-forward="true" selection-start-line="1072" selection-start-column="14" selection-end-line="1072" selection-end-column="14" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/token/signtoken.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="583">
<caret line="119" column="0" lean-forward="false" selection-start-line="119" selection-start-column="0" selection-end-line="119" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/cmd/verify.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="613">
<caret line="53" column="27" lean-forward="false" selection-start-line="53" selection-start-column="22" selection-end-line="53" selection-end-column="27" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/cmd/sign.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="602">
<caret line="51" column="48" lean-forward="false" selection-start-line="51" selection-start-column="48" selection-end-line="51" selection-end-column="48" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/token/showtoken.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="527">
<caret line="39" column="24" lean-forward="true" selection-start-line="39" selection-start-column="24" selection-end-line="39" selection-end-column="24" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/token/token.go">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="251">
<caret line="38" column="5" lean-forward="false" selection-start-line="38" selection-start-column="5" selection-end-line="38" selection-end-column="5" />
<folding />
</state>
</provider>
</entry>
</component>
</project>

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2018 ehlxr <ehlxr.me@gmail.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.

84
cmd/root.go Normal file
View File

@ -0,0 +1,84 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package cmd
import (
"fmt"
"os"
homedir "github.com/mitchellh/go-homedir"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "jwt",
Short: "JWT(Json Web Token) 工具",
Long: `JWT(Json Web Token)
JWT`,
Version: "v0.0.1",
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.jwt.yaml)")
// rootCmd.Flags().BoolP("help", "h", false, "path to JWT token to verify or '-' to read from stdin")
rootCmd.Flags().BoolP("version", "v", false, "show version of the jwt.")
}
// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" {
// Use config file from the flag.
viper.SetConfigFile(cfgFile)
} else {
// Find home directory.
home, err := homedir.Dir()
if err != nil {
fmt.Println(err)
os.Exit(1)
}
// Search config in home directory with name ".jwt" (without extension).
viper.AddConfigPath(home)
viper.SetConfigName(".jwt")
}
viper.AutomaticEnv() // read in environment variables that match
// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}

49
cmd/show.go Normal file
View File

@ -0,0 +1,49 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package cmd
import (
"fmt"
"os"
"github.com/ehlxr/jwt/token"
"github.com/spf13/cobra"
)
// showCmd represents the show command
var showCmd = &cobra.Command{
Use: "show",
Short: "查看 JWT Token",
Long: `
JWT Token`,
Run: func(cmd *cobra.Command, args []string) {
if err := token.ShowToken(cmd); err != nil {
fmt.Println(err)
os.Exit(1)
}
},
}
func init() {
rootCmd.AddCommand(showCmd)
showCmd.Flags().StringP("token", "t", "", "path or arg of JWT token to verify, '-' to read from clipboard")
}

52
cmd/sign.go Normal file
View File

@ -0,0 +1,52 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package cmd
import (
"fmt"
"os"
"github.com/ehlxr/jwt/token"
"github.com/spf13/cobra"
)
// signCmd represents the sign command
var signCmd = &cobra.Command{
Use: "sign",
Short: "JWT 签名",
Long: `
JWT `,
Run: func(cmd *cobra.Command, args []string) {
if err := token.SignToken(cmd); err != nil {
fmt.Println(err)
os.Exit(1)
}
},
}
func init() {
rootCmd.AddCommand(signCmd)
signCmd.Flags().StringP("data", "d", "", "path or json to claims object to sign, '-' to read from clipboard, or '+' to use only -claim args")
signCmd.Flags().StringP("key", "k", "", "path of keyfile or key argument")
signCmd.Flags().VarP(make(token.ArgList), "claims", "c", "add additional claims. may be used more than once")
signCmd.Flags().VarP(make(token.ArgList), "header", "H", "add additional header params. may be used more than once")
}

52
cmd/verify.go Normal file
View File

@ -0,0 +1,52 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package cmd
import (
"os"
"github.com/ehlxr/jwt/token"
"fmt"
"github.com/spf13/cobra"
)
// verifyCmd represents the verify command
var verifyCmd = &cobra.Command{
Use: "verify",
Short: "JWT token 验证",
Long: `
JWT token `,
Run: func(cmd *cobra.Command, args []string) {
if err := token.VerifyToken(cmd); err != nil {
fmt.Println(err)
os.Exit(1)
}
},
}
func init() {
rootCmd.AddCommand(verifyCmd)
verifyCmd.Flags().StringP("token", "t", "", "path or arg of JWT token to verify, '-' to read from clipboard")
verifyCmd.Flags().StringP("key", "k", "", "path of keyfile or key argument")
}

6
demo.json Normal file
View File

@ -0,0 +1,6 @@
{
"foo": "bar",
"exp": "2108-02-03",
"info": "jjjkk",
"other": "靠捡垃圾困了就睡打发士大夫斯柯达房间爱劳动法"
}

1
demo.token Normal file
View File

@ -0,0 +1 @@
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOiIyMTA4LTAyLTAzIiwiZm9vIjoiYmFyIiwiaW5mbyI6ImpqamtrIiwib3RoZXIiOiLpnaDmjaHlnoPlnL7lm7DkuoblsLHnnaHmiZPlj5Hlo6vlpKflpKvmlq_mn6_ovr7miL_pl7TniLHlirPliqjms5UifQ.lwIz_fjoxHkgaBLUnBsRO0_zCmx4bEKNP_noW0dIGSSV5dPReb_E41Dg38G0ZB6tUFgH9k7aKsUUdMO3-ixRQ-nVT7qryLVti72G7Bpxy-_0FcwPWsvOl1ic8wCMtXLcL2FmcxFt4VC7nky1iAMCYn0iWyBxuPboNxBYNJF2TYB5rsfoLGgQ-okFVahZWDrdiepIlwFh-SkzrgLYzFhUgfCvCOFyTn65aNzJxY_3vxd4OSl6ks8C6J1qF7FZbFVFpcaHebZHjqg2rS3q0CdhN1IpGhEHC4dktpbeAzUYTPaohJWa-Rftthg4iM9DOFz8NBB_rNxyCYBfsbcywk8X2g

27
key/private-key.pem Normal file
View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtLcqUewX4sOPUUcocUi4EMMi25I52j9AHpphV4xZ5uUBzUuE
sEuomPhvpElrVGAnla6856nrsSOTnw/pQ+wHkZLXXBbJOqdOH8wohch6v3lJoJDS
FsCc+Y2OfolxZ8qz1Qq+AyvFGv4NIM0rWsfosrSsMDnQzLFtUoAfCMGU4uas2H1u
Wfh+dDaABgxshAtmBuTyFJ/q36mGAznGzN7jVUSxv+pgI6AyEgxiIKOmFrz9qm6N
s/H9fONQznnZouFZc0p3PME4xJcpdjET2tpACBZr6p7znFCm7t2BMrC37wznHUxC
xP3XOugH9fs90EXV3XwPHZTAkvxvs8fpeDfGhwIDAQABAoIBAQCbsyhqNuEJhnZn
j8h/eijkgEv7JAxmRpKnC1oNBSa8MdkQmR00i6sySPJfeMZZhxLz+v5VFuiz0TQy
GpJe6/BFc1/LvvIXb+h2qv7K7UUczZIrHjt0UPWuaVE5IpAr3dB9IGk/8Ck9rV+A
QGU3LQAHYHTuhBGrGr9XEn4qnCb8KlH/h12YEomIlp0+5TG6j4U6gzCJYM8MSmmP
ms3JYP3jCvCD+UWcHXcWd/MAs4vfQAcCSvrrwrjHB0SZNAgUeIYxiXje1sKS5SU5
tCKp7B7+PwBXkOMPPBxB93GsEmc6Tnw48hvl/xhOThOQ3zI608mzd83YQ7XU0cxO
0LtAdyURAoGBAOFD3Ba1mL4MdYuSMpEH4Teu+rmuVBvF9tIA8uI73ZZDxOrklZRr
XUtDcDwlsaSgk2ATz15+Rr+pYT3H3xl95P/xj2LG5SNY2OmiANALYHm71wDAa3xD
th5p6QJ1wqQxzEBewwqXrm49YZr5eNU+rvTjsW4YcSB9ObYBbSUGvqf5AoGBAM1f
Qu4pYrIfkPFhgDQaepDhZ41NGIaDmukZcorVPnliy4+anMoivvVjVNkUb7FyHm8h
Fo2q6gSyeGDVGg/6QbMrzIrN5fqjCK4M4cBwd3sboctjI8fwJQB2+Wb6iOCQMU1W
DbJ/edhOdLZ71lQMd+f5iQvhiZJPGLZnAxHyhoJ/AoGBANqvrU9illkR8V9A29RO
SQds2L1ADykzQ01WXHTi11iUi+vZY5lFrbluS9woX8/Jj6k7MhqzDm3suplmmyC9
Rn5ufNvQ6QwqqdIOUymlkdA8WhrBstddSMU33lxkBESwj3CCTmjPHiipcEMqI3Mp
umHFVi/ijJiU2Vzm/5VtedPJAoGAQ5WI0hVefF209ipu5TadhRYYXMC1RHcEwJb2
QcfhMlMXyB9KX57Flr1ki7eU9iEm8M1DvcU0E+2jfcJDPGTPwCW2vyr49t02Gwj0
Nb8NIr86JFNwz/gwRRHiC0iBSN1KzDd4dHhM4akX8YGZS7l6sCVHO1iyTCqpaEVI
FlzodQMCgYEAlMyxMLwaePE1NPgPqUeLcjfId42AZ64sVjoNG3awzj6pr3kV9mjp
3GxFFDLdELZcsD5aJ5YSFbjMvUqSyyuFlZOAut06iUtPAN7fC57PdXGpcf2YkoK3
PPK4mrwSlB4Onk8BQ3HfyGC5jzNsl+mnUHrRljWyzhdwQXtj65zQCD4=
-----END RSA PRIVATE KEY-----

9
key/public-key.pem Normal file
View File

@ -0,0 +1,9 @@
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtLcqUewX4sOPUUcocUi4
EMMi25I52j9AHpphV4xZ5uUBzUuEsEuomPhvpElrVGAnla6856nrsSOTnw/pQ+wH
kZLXXBbJOqdOH8wohch6v3lJoJDSFsCc+Y2OfolxZ8qz1Qq+AyvFGv4NIM0rWsfo
srSsMDnQzLFtUoAfCMGU4uas2H1uWfh+dDaABgxshAtmBuTyFJ/q36mGAznGzN7j
VUSxv+pgI6AyEgxiIKOmFrz9qm6Ns/H9fONQznnZouFZc0p3PME4xJcpdjET2tpA
CBZr6p7znFCm7t2BMrC37wznHUxCxP3XOugH9fs90EXV3XwPHZTAkvxvs8fpeDfG
hwIDAQAB
-----END PUBLIC KEY-----

27
main.go Normal file
View File

@ -0,0 +1,27 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package main
import "github.com/ehlxr/jwt/cmd"
func main() {
cmd.Execute()
}

68
token/showtoken.go Normal file
View File

@ -0,0 +1,68 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package token
import (
"fmt"
"os"
"regexp"
jwt "github.com/dgrijalva/jwt-go"
"github.com/spf13/cobra"
)
// showToken pretty-prints the token on the command line.
func ShowToken(cmd *cobra.Command) error {
flagToken := cmd.LocalFlags().Lookup("token").Value.String()
flagDebug := promptDebug()
flagCompact := promptCompact()
// get the token
tokData, err := loadData(flagToken)
if err != nil {
return fmt.Errorf("Couldn't read token: %v", err)
}
// trim possible whitespace from token
tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
if flagDebug {
fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
}
token, err := jwt.Parse(string(tokData), nil)
if token == nil {
return fmt.Errorf("malformed token: %v", err)
}
// Print the token details
fmt.Println("Header:")
if err := printJSON(token.Header, flagCompact); err != nil {
return fmt.Errorf("Failed to output header: %v", err)
}
fmt.Println("Claims:")
if err := printJSON(token.Claims, flagCompact); err != nil {
return fmt.Errorf("Failed to output claims: %v", err)
}
return nil
}

122
token/signtoken.go Normal file
View File

@ -0,0 +1,122 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package token
import (
"encoding/json"
"fmt"
"os"
"github.com/atotto/clipboard"
jwt "github.com/dgrijalva/jwt-go"
"github.com/spf13/cobra"
)
// Create, sign, and output a token. This is a great, simple example of
// how to use this library to create and sign a token.
func SignToken(cmd *cobra.Command) error {
flagData := cmd.LocalFlags().Lookup("data").Value.String()
flagClaims := cmd.LocalFlags().Lookup("claims").Value.(ArgList)
flagHead := cmd.LocalFlags().Lookup("header").Value.(ArgList)
flagKey := cmd.LocalFlags().Lookup("key").Value.String()
flagDebug := promptDebug()
flagAlg, err := promptAlg()
if err != nil {
return fmt.Errorf("Prompt flagAlg failed %v\n", err)
}
// get the token data from command line arguments
tokData, err := loadData(flagData)
if err != nil {
return fmt.Errorf("Couldn't read data: %v", err)
} else if flagDebug {
fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
fmt.Fprintf(os.Stderr, "Token data: %v \n", string(tokData))
}
// parse the JSON of the claims
var claims jwt.MapClaims
if err := json.Unmarshal(tokData, &claims); err != nil {
return fmt.Errorf("Couldn't parse claims JSON: %v", err)
}
// add command line claims
if len(flagClaims) > 0 {
for k, v := range flagClaims {
claims[k] = v
}
}
// get the key
var key interface{}
key, err = loadData(flagKey)
if err != nil {
return fmt.Errorf("Couldn't read key: %v", err)
}
// get the signing alg
alg := jwt.GetSigningMethod(flagAlg)
if alg == nil {
return fmt.Errorf("Couldn't find signing method alg: %v", flagAlg)
}
// create a new token
token := jwt.NewWithClaims(alg, claims)
// add command line headers
if len(flagHead) > 0 {
for k, v := range flagHead {
token.Header[k] = v
}
}
if isEs(flagAlg) {
if k, ok := key.([]byte); !ok {
return fmt.Errorf("Couldn't convert key data to key")
} else {
key, err = jwt.ParseECPrivateKeyFromPEM(k)
if err != nil {
return err
}
}
} else if isRs(flagAlg) {
if k, ok := key.([]byte); !ok {
return fmt.Errorf("Couldn't convert key data to key")
} else {
key, err = jwt.ParseRSAPrivateKeyFromPEM(k)
if err != nil {
return err
}
}
}
if out, err := token.SignedString(key); err == nil {
fmt.Println(out)
clipboard.WriteAll(out)
} else {
return fmt.Errorf("Error signing token: %v", err)
}
return nil
}

163
token/token.go Normal file
View File

@ -0,0 +1,163 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package token
import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"
"github.com/atotto/clipboard"
"github.com/manifoldco/promptui"
)
// Helper func: Read input from specified file or string
func loadData(p string) ([]byte, error) {
if p == "" {
return nil, fmt.Errorf("No path or arg specified")
}
var rdr io.Reader
if p == "-" {
t, _ := clipboard.ReadAll()
fmt.Printf("read data from clipboard: %s\n", t)
rdr = strings.NewReader(t)
} else if p == "+" {
return []byte("{}"), nil
} else {
is, path := isPath(p)
if is {
if f, err := os.Open(path); err == nil {
rdr = f
defer f.Close()
} else {
return nil, err
}
} else {
rdr = strings.NewReader(p)
}
}
return ioutil.ReadAll(rdr)
}
func isPath(path string) (bool, string) {
p, err := filepath.Abs("")
if err != nil {
log.Fatal(err)
}
absPath := filepath.Join(p, strings.Replace(path, p, "", 1))
_, err = os.Stat(absPath)
if err == nil {
return true, absPath
}
return false, ""
}
// Print a json object in accordance with the prophecy (or the command line options)
func printJSON(j interface{}, flagCompact bool) error {
var out []byte
var err error
if flagCompact == false {
out, err = json.MarshalIndent(j, "", " ")
} else {
out, err = json.Marshal(j)
}
if err == nil {
fmt.Println(string(out))
}
return err
}
func isEs(flagAlg string) bool {
return strings.HasPrefix(flagAlg, "ES")
}
func isRs(flagAlg string) bool {
return strings.HasPrefix(flagAlg, "RS")
}
func promptAlg() (string, error) {
prompt := promptui.SelectWithAdd{
Label: "select a signing algorithm identifier",
Items: []string{"HS256", "RS256"},
AddLabel: "Other",
}
_, flagAlg, err := prompt.Run()
if err != nil {
return "", fmt.Errorf("Prompt flagAlg failed %v\n", err)
}
return flagAlg, nil
}
func promptDebug() bool {
prompt := promptui.Prompt{
Label: "print out all kinds of debug data",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return false
}
return true
}
func promptCompact() bool {
prompt := promptui.Prompt{
Label: "output compact JSON",
IsConfirm: true,
}
if _, err := prompt.Run(); err != nil {
return false
}
return true
}
type ArgList map[string]string
func (l ArgList) String() string {
data, _ := json.Marshal(l)
return string(data)
}
func (l ArgList) Set(arg string) error {
parts := strings.SplitN(arg, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("Invalid argument '%v'. Must use format 'key=value'. %v", arg, parts)
}
l[parts[0]] = parts[1]
return nil
}
func (l ArgList) Type() string {
return "argList"
}

93
token/verifytoken.go Normal file
View File

@ -0,0 +1,93 @@
// Copyright © 2018 ehlxr <ehlxr.me@gmail.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.
package token
import (
"fmt"
"os"
"regexp"
jwt "github.com/dgrijalva/jwt-go"
"github.com/spf13/cobra"
)
// Verify a token and output the claims. This is a great example
// of how to verify and view a token.
func VerifyToken(cmd *cobra.Command) error {
flagToken := cmd.LocalFlags().Lookup("token").Value.String()
flagKey := cmd.LocalFlags().Lookup("key").Value.String()
flagCompact := promptCompact()
flagDebug := promptDebug()
flagAlg, err := promptAlg()
if err != nil {
return fmt.Errorf("Prompt flagAlg failed %v\n", err)
}
// get the token
tokData, err := loadData(flagToken)
if err != nil {
return fmt.Errorf("Couldn't read token: %v", err)
}
// trim possible whitespace from token
tokData = regexp.MustCompile(`\s*$`).ReplaceAll(tokData, []byte{})
if flagDebug {
fmt.Fprintf(os.Stderr, "Token len: %v bytes\n", len(tokData))
}
// Parse the token. Load the key from command line option
token, err := jwt.Parse(string(tokData), func(t *jwt.Token) (interface{}, error) {
data, err := loadData(flagKey)
if err != nil {
return nil, err
}
if isEs(flagAlg) {
return jwt.ParseECPublicKeyFromPEM(data)
} else if isRs(flagAlg) {
return jwt.ParseRSAPublicKeyFromPEM(data)
}
return data, nil
})
// Print some debug data
if flagDebug && token != nil {
fmt.Fprintf(os.Stderr, "Header:\n%v\n", token.Header)
fmt.Fprintf(os.Stderr, "Claims:\n%v\n", token.Claims)
}
// Print an error if we can't parse for some reason
if err != nil {
return fmt.Errorf("Couldn't parse token: %v", err)
}
// Is token invalid?
if !token.Valid {
return fmt.Errorf("Token is invalid")
}
// Print the token details
if err := printJSON(token.Claims, flagCompact); err != nil {
return fmt.Errorf("Failed to output claims: %v", err)
}
return nil
}