Forráskód Böngészése

Merge pull request #8961 from thalesmg/drop-license-file-master

chore: drop support for license files
Zaiming (Stone) Shi 3 éve
szülő
commit
6991b42f14

+ 9 - 15
bin/emqx

@@ -417,7 +417,7 @@ call_hocon() {
 ## and parsing HOCON config + environment variables is a non-trivial task
 CONF_KEYS=( 'node.data_dir' 'node.name' 'node.cookie' 'node.db_backend' 'cluster.proto_dist' )
 if [ "$IS_ENTERPRISE" = 'yes' ]; then
-    CONF_KEYS+=( 'license.type' 'license.file' 'license.key' )
+    CONF_KEYS+=( 'license.key' )
 fi
 
 if [ "$IS_BOOT_COMMAND" = 'yes' ]; then
@@ -499,22 +499,16 @@ check_license() {
         return 0
     fi
 
-    file_license="${EMQX_LICENSE__FILE:-$(get_boot_config 'license.file')}"
+    key_license="${EMQX_LICENSE__KEY:-$(get_boot_config 'license.key')}"
 
-    if [[ -n "$file_license" && ("$file_license" != "undefined") ]]; then
-        call_nodetool check_license_file "$file_license"
+    if [[ -n "$key_license" && ("$key_license" != "undefined") ]]; then
+      call_nodetool check_license_key "$key_license"
     else
-        key_license="${EMQX_LICENSE__KEY:-$(get_boot_config 'license.key')}"
-
-        if [[ -n "$key_license" && ("$key_license" != "undefined") ]]; then
-            call_nodetool check_license_key "$key_license"
-        else
-            set +x
-            echoerr "License not found."
-            echoerr "Please specify one via EMQX_LICENSE__KEY or EMQX_LICENSE__FILE variables"
-            echoerr "or via license.key|file in emqx_enterprise.conf."
-            return 1
-        fi
+      set +x
+      echoerr "License not found."
+      echoerr "Please specify one via the EMQX_LICENSE__KEY variable"
+      echoerr "or via license.key in emqx-enterprise.conf."
+      return 1
     fi
 }
 

+ 1 - 3
bin/nodetool

@@ -25,9 +25,7 @@ main(Args) ->
             %% forward the call to hocon_cli
             hocon_cli:main(Rest);
         ["check_license_key", Key] ->
-            check_license(#{type => key, key => list_to_binary(Key)});
-        ["check_license_file", File] ->
-            check_license(#{type => file, file => list_to_binary(File)});
+            check_license(#{key => list_to_binary(Key)});
         _ ->
             do(Args)
     end.

+ 0 - 7
lib-ee/emqx_license/etc/emqx_license.conf

@@ -1,7 +0,0 @@
-license {
-    type = key
-    # The default license has 1000 connections limit, it is issued on 20220419 and valid for 5 years (1825 days)
-    key = "MjIwMTExCjAKMTAKRXZhbHVhdGlvbgpjb250YWN0QGVtcXguaW8KZGVmYXVsdAoyMDIyMDQxOQoxODI1CjEwMDAK.MEQCICbgRVijCQov2hrvZXR1mk9Oa+tyV1F5oJ6iOZeSHjnQAiB9dUiVeaZekDOjztk+NCWjhk4PG8tWfw2uFZWruSzD6g=="
-    connection_low_watermark = 75%,
-    connection_high_watermark = 80%
-}

+ 0 - 11
lib-ee/emqx_license/i18n/emqx_license_http_api.conf

@@ -10,17 +10,6 @@ emqx_license_http_api {
     }
   }
 
-  desc_license_file_api {
-    desc {
-      en: "Upload a license file"
-      zh: "上传一个许可证文件"
-    }
-    label: {
-      en: "Update license"
-      zh: "更新许可证"
-    }
-  }
-
   desc_license_key_api {
     desc {
       en: "Update a license key"

+ 6 - 28
lib-ee/emqx_license/i18n/emqx_license_schema_i18n.conf

@@ -2,16 +2,16 @@ emqx_license_schema {
   license_root {
     desc {
       en: "Defines the EMQX Enterprise license. \n\n"
-          "A license is either a `key` or a `file`.\n"
-          "When `key` and `file` are both configured, `key` is used.\n"
+          "\n"
+          "The default license has 1000 connections limit, it is "
+          "issued on 2022-04-19 and valid for 5 years (1825 days).\n"
           "\n"
           "EMQX comes with a default trial license.  For production use, please \n"
           "visit https://www.emqx.com/apply-licenses/emqx to apply."
       zh: "EMQX企业许可证。\n"
-          "许可证是一个 `key` 或一个 `file`。\n"
-          "当 `key` 和 `file` 同时被配置时,优先使用 `key`。\n"
-          "\n"
-          "EMQX 自带一个默认的试用许可证,若需要在生产环境部署,\n"
+          "EMQX 自带一个默认的试用许可证,"
+          "默认试用许可允许最多接入 1000 个连接,签发时间是 2022年4月19日,有效期是 5 年(1825 天)。"
+          "若需要在生产环境部署,\n"
           "请访问 https://www.emqx.com/apply-licenses/emqx 来申请。\n"
     }
     label {
@@ -20,17 +20,6 @@ emqx_license_schema {
     }
   }
 
-  license_type_field {
-    desc {
-      en: "License type"
-      zh: "许可证类型"
-    }
-    label {
-      en: "License type"
-      zh: "许可证类型"
-    }
-  }
-
   key_field {
     desc {
       en: "License string"
@@ -42,17 +31,6 @@ emqx_license_schema {
     }
   }
 
-  file_field {
-    desc {
-      en: "Path to the license file"
-      zh: "许可证文件的路径"
-    }
-    label {
-      en: "Path to the license file"
-      zh: "许可证文件的路径"
-    }
-  }
-
   connection_low_watermark_field {
     desc {
       en: "Low watermark limit below which license connection quota usage alarms are deactivated"

+ 1 - 1
lib-ee/emqx_license/src/emqx_license.app.src

@@ -1,6 +1,6 @@
 {application, emqx_license, [
     {description, "EMQX License"},
-    {vsn, "5.0.2"},
+    {vsn, "5.0.3"},
     {modules, []},
     {registered, [emqx_license_sup]},
     {applications, [kernel, stdlib]},

+ 3 - 91
lib-ee/emqx_license/src/emqx_license.erl

@@ -21,11 +21,7 @@
     unload/0,
     read_license/0,
     read_license/1,
-    update_file/1,
-    update_file_contents/1,
-    update_key/1,
-    license_dir/0,
-    save_and_backup_license/1
+    update_key/1
 ]).
 
 -define(CONF_KEY_PATH, [license]).
@@ -57,35 +53,6 @@ unload() ->
     emqx_conf:remove_handler(?CONF_KEY_PATH),
     emqx_license_cli:unload().
 
--spec license_dir() -> file:filename().
-license_dir() ->
-    filename:join([emqx:data_dir(), licenses]).
-
-%% Subdirectory relative to data dir.
--spec relative_license_path() -> file:filename().
-relative_license_path() ->
-    filename:join([licenses, "emqx.lic"]).
-
--spec update_file(binary() | string()) ->
-    {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}.
-update_file(Filename) when is_binary(Filename); is_list(Filename) ->
-    case file:read_file(Filename) of
-        {ok, Contents} ->
-            update_file_contents(Contents);
-        {error, Error} ->
-            {error, Error}
-    end.
-
--spec update_file_contents(binary() | string()) ->
-    {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}.
-update_file_contents(Contents) when is_binary(Contents) ->
-    Result = emqx_conf:update(
-        ?CONF_KEY_PATH,
-        {file, Contents},
-        #{rawconf_with_defaults => true, override_to => local}
-    ),
-    handle_config_update_result(Result).
-
 -spec update_key(binary() | string()) ->
     {ok, emqx_config:update_result()} | {error, emqx_config:update_error()}.
 update_key(Value) when is_binary(Value); is_list(Value) ->
@@ -147,18 +114,10 @@ del_license_hook() ->
     _ = emqx_hooks:del('client.connect', {?MODULE, check, []}),
     ok.
 
-do_update({file, NewContents}, Conf) ->
-    Res = emqx_license_proto_v2:save_and_backup_license(mria_mnesia:running_nodes(), NewContents),
-    %% assert
-    true = lists:all(fun(X) -> X =:= {ok, ok} end, Res),
-    %% Must be relative to the data dir, since different nodes might
-    %% have different data directories configured...
-    LicensePath = relative_license_path(),
-    maps:remove(<<"key">>, Conf#{<<"type">> => file, <<"file">> => LicensePath});
 do_update({key, Content}, Conf) when is_binary(Content); is_list(Content) ->
     case emqx_license_parser:parse(Content) of
         {ok, _License} ->
-            maps:remove(<<"file">>, Conf#{<<"type">> => key, <<"key">> => Content});
+            Conf#{<<"key">> => Content};
         {error, Reason} ->
             erlang:throw(Reason)
     end;
@@ -166,57 +125,10 @@ do_update({key, Content}, Conf) when is_binary(Content); is_list(Content) ->
 do_update(_Other, Conf) ->
     Conf.
 
-save_and_backup_license(NewLicenseKey) ->
-    %% Must be relative to the data dir, since different nodes might
-    %% have different data directories configured...
-    CurrentLicensePath = filename:join(emqx:data_dir(), relative_license_path()),
-    LicenseDir = filename:dirname(CurrentLicensePath),
-    case filelib:ensure_dir(CurrentLicensePath) of
-        ok -> ok;
-        {error, EnsureError} -> throw({error_creating_license_dir, EnsureError})
-    end,
-    case file:read_file(CurrentLicensePath) of
-        {ok, NewLicenseKey} ->
-            %% same contents; nothing to do.
-            ok;
-        {ok, _OldContents} ->
-            Time = calendar:system_time_to_rfc3339(erlang:system_time(second)),
-            BackupPath = filename:join([
-                LicenseDir,
-                "emqx.lic." ++ Time ++ ".backup"
-            ]),
-            case file:copy(CurrentLicensePath, BackupPath) of
-                {ok, _} -> ok;
-                {error, CopyError} -> throw({error_backing_up_license, CopyError})
-            end,
-            ok;
-        {error, enoent} ->
-            ok;
-        {error, Error} ->
-            throw({error_reading_existing_license, Error})
-    end,
-    case file:write_file(CurrentLicensePath, NewLicenseKey) of
-        ok -> ok;
-        {error, WriteError} -> throw({error_writing_license, WriteError})
-    end,
-    ok.
-
 check_max_clients_exceeded(MaxClients) ->
     emqx_license_resources:connection_count() > MaxClients * 1.1.
 
-read_license(#{type := file, file := Filename}) ->
-    case file:read_file(Filename) of
-        {ok, Content} ->
-            emqx_license_parser:parse(Content);
-        {error, _} = Error ->
-            %% Could be a relative path in data folder after update.
-            FilenameDataDir = filename:join(emqx:data_dir(), Filename),
-            case file:read_file(FilenameDataDir) of
-                {ok, Content} -> emqx_license_parser:parse(Content);
-                _Error -> Error
-            end
-    end;
-read_license(#{type := key, key := Content}) ->
+read_license(#{key := Content}) ->
     emqx_license_parser:parse(Content).
 
 handle_config_update_result({error, {post_config_update, ?MODULE, Error}}) ->

+ 0 - 17
lib-ee/emqx_license/src/emqx_license_cli.erl

@@ -19,21 +19,6 @@
 load() ->
     ok = emqx_ctl:register_command(license, {?MODULE, license}, []).
 
-license(["reload"]) ->
-    case emqx:get_config([license]) of
-        #{file := Filename} ->
-            license(["reload", Filename]);
-        #{key := _Key} ->
-            ?PRINT_MSG("License is not configured as a file, please specify file explicitly~n")
-    end;
-license(["reload", Filename]) ->
-    case emqx_license:update_file(Filename) of
-        {ok, Warnings} ->
-            ok = print_warnings(Warnings),
-            ok = ?PRINT_MSG("ok~n");
-        {error, Reason} ->
-            ?PRINT("Error: ~p~n", [Reason])
-    end;
 license(["update", EncodedLicense]) ->
     case emqx_license:update_key(EncodedLicense) of
         {ok, Warnings} ->
@@ -56,8 +41,6 @@ license(_) ->
     emqx_ctl:usage(
         [
             {"license info", "Show license info"},
-            {"license reload [<File>]",
-                "Reload license from a file specified with an absolute path"},
             {"license update License", "Update license given as a string"}
         ]
     ).

+ 9 - 56
lib-ee/emqx_license/src/emqx_license_http_api.erl

@@ -17,9 +17,7 @@
 ]).
 
 -export([
-    '/license'/2,
-    '/license/key'/2,
-    '/license/file'/2
+    '/license'/2
 ]).
 
 -define(BAD_REQUEST, 'BAD_REQUEST').
@@ -31,9 +29,7 @@ api_spec() ->
 
 paths() ->
     [
-        "/license",
-        "/license/key",
-        "/license/file"
+        "/license"
     ].
 
 schema("/license") ->
@@ -53,32 +49,7 @@ schema("/license") ->
                     }
                 )
             }
-        }
-    };
-schema("/license/file") ->
-    #{
-        'operationId' => '/license/file',
-        post => #{
-            tags => [<<"license">>],
-            summary => <<"Upload license file">>,
-            description => ?DESC("desc_license_file_api"),
-            'requestBody' => emqx_dashboard_swagger:file_schema(filename),
-            responses => #{
-                200 => emqx_dashboard_swagger:schema_with_examples(
-                    map(),
-                    #{
-                        sample_license_info => #{
-                            value => sample_license_info_response()
-                        }
-                    }
-                ),
-                400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad license file">>)
-            }
-        }
-    };
-schema("/license/key") ->
-    #{
-        'operationId' => '/license/key',
+        },
         post => #{
             tags => [<<"license">>],
             summary => <<"Update license key">>,
@@ -105,7 +76,7 @@ schema("/license/key") ->
                         }
                     }
                 ),
-                400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad license file">>)
+                400 => emqx_dashboard_swagger:error_codes([?BAD_REQUEST], <<"Bad license key">>)
             }
         }
     }.
@@ -126,30 +97,12 @@ sample_license_info_response() ->
 error_msg(Code, Msg) ->
     #{code => Code, message => emqx_misc:readable_error_msg(Msg)}.
 
+%% read license info
 '/license'(get, _Params) ->
     License = maps:from_list(emqx_license_checker:dump()),
-    {200, License}.
-
-'/license/file'(post, #{body := #{<<"filename">> := #{type := _} = File}}) ->
-    [{_Filename, Contents}] = maps:to_list(maps:without([type], File)),
-    case emqx_license:update_file_contents(Contents) of
-        {error, Error} ->
-            ?SLOG(error, #{
-                msg => "bad_license_file",
-                reason => Error
-            }),
-            {400, error_msg(?BAD_REQUEST, <<"Bad license file">>)};
-        {ok, _} ->
-            ?SLOG(info, #{
-                msg => "updated_license_file"
-            }),
-            License = maps:from_list(emqx_license_checker:dump()),
-            {200, License}
-    end;
-'/license/file'(post, _Params) ->
-    {400, error_msg(?BAD_REQUEST, <<"Invalid request params">>)}.
-
-'/license/key'(post, #{body := #{<<"key">> := Key}}) ->
+    {200, License};
+%% set/update license
+'/license'(post, #{body := #{<<"key">> := Key}}) ->
     case emqx_license:update_key(Key) of
         {error, Error} ->
             ?SLOG(error, #{
@@ -162,5 +115,5 @@ error_msg(Code, Msg) ->
             License = maps:from_list(emqx_license_checker:dump()),
             {200, License}
     end;
-'/license/key'(post, _Params) ->
+'/license'(post, _Params) ->
     {400, error_msg(?BAD_REQUEST, <<"Invalid request params">>)}.

+ 1 - 2
lib-ee/emqx_license/src/emqx_license_parser.erl

@@ -20,8 +20,7 @@
 >>).
 
 -define(LICENSE_PARSE_MODULES, [
-    emqx_license_parser_v20220101,
-    emqx_license_parser_legacy
+    emqx_license_parser_v20220101
 ]).
 
 -type license_data() :: term().

+ 0 - 265
lib-ee/emqx_license/src/emqx_license_parser_legacy.erl

@@ -1,265 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved.
-%%--------------------------------------------------------------------
-
--module(emqx_license_parser_legacy).
-
--behaviour(emqx_license_parser).
-
--include_lib("public_key/include/public_key.hrl").
--include("emqx_license.hrl").
-
--elvis([{elvis_style, atom_naming_convention, disable}]).
-
--define(CACERT, <<
-    "-----BEGIN CERTIFICATE-----\n"
-    "MIIDVDCCAjwCCQCckt8CVupoRDANBgkqhkiG9w0BAQsFADBsMQswCQYDVQQGEwJD\n"
-    "TjERMA8GA1UECAwIWmhlamlhbmcxETAPBgNVBAcMCEhhbmd6aG91MQwwCgYDVQQK\n"
-    "DANFTVExDDAKBgNVBAsMA0VNUTEbMBkGA1UEAwwSRU1RWCBFbnRlcnByaXNlIHY1\n"
-    "MB4XDTIyMDQwODE1MTA1M1oXDTIzMDQwODE1MTA1M1owbDELMAkGA1UEBhMCQ04x\n"
-    "ETAPBgNVBAgMCFpoZWppYW5nMREwDwYDVQQHDAhIYW5nemhvdTEMMAoGA1UECgwD\n"
-    "RU1RMQwwCgYDVQQLDANFTVExGzAZBgNVBAMMEkVNUVggRW50ZXJwcmlzZSB2NTCC\n"
-    "ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMiYB/gbxCSErWL8sNZHkP4s\n"
-    "VTyeBho5T+5Uyp2S95qmcj10FBGi50ZnEN/62vMWED3HzEXsp6pq2Jk+Of3g9rSu\n"
-    "63V082HzlqFNHFzUDGkEu23tWyxeEKwBGyYRLIJI1/az99Jq82Qo0UZ5ELVpouAz\n"
-    "QVOKjpehHvWgEuWmPi+w1uuOieO08nO4AAOLHWcNOChgV50sl88gbz2n/kAcjqzl\n"
-    "1MQXMXoRzfzseNf3bmBV0keNFOpcqePTWCeshFFVkqeKMbK5HIKsnoDSl3VtQ/KK\n"
-    "iV88WpW4f0QfGGJV/gHt++4BAZS3nzxXUhGA0Tf2o7N1CHqnXuottJVcgzyIxHEC\n"
-    "AwEAATANBgkqhkiG9w0BAQsFAAOCAQEANh3ofOa9Aoqb7gUoTb6dNj883aHZ4aHi\n"
-    "kQVo4fVc4IH1MLVNuH/H/aqQ+YtRbbE4YT0icApJFa8qriv8afD9reh5/6ySdsms\n"
-    "RAXSogCuAPk2DwT1fyQa6A45x5EBpgwW10rYhwa5JJi6YKPpWS/Uo1Fgk9YGmeW4\n"
-    "FgGWYvWQHQIXhjfTC0wJPXlsDB2AB7xMINlOSfg/Bz8mhz7iOjM4pkvnTj17JrgR\n"
-    "VQLAj4NFAvdLFFjhZarFtCjPiCE4gb5YZI/Os4iMenD1ZWnYy9Sy7JSNXhWda6e2\n"
-    "WGl1AsyDsVPdvAzcB5ymrLnptCzZYT29PSubmCHS9nFgT6hkWCam4g==\n"
-    "-----END CERTIFICATE-----"
->>).
-
-%% emqx_license_parser callbacks
--export([
-    parse/2,
-    dump/1,
-    customer_type/1,
-    license_type/1,
-    expiry_date/1,
-    max_connections/1
-]).
-
-%%--------------------------------------------------------------------
-%% emqx_license_parser API
-%%--------------------------------------------------------------------
-
-%% Sample parsed data:
-%% #{customer => <<"EMQ X Evaluation">>,
-%%   email => "contact@emqx.io",
-%%   permits =>
-%%       #{customer_type => 10,
-%%         enabled_plugins =>
-%%             [emqx_backend_redis,emqx_backend_mysql,
-%%              emqx_backend_pgsql,emqx_backend_mongo,
-%%              emqx_backend_cassa,emqx_bridge_kafka,
-%%              emqx_bridge_rabbit],
-%%         max_connections => 10,type => 1},
-%%   product => "EMQX Enterprise",
-%%   validity =>
-%%       {{{2020,6,20},{3,2,52}},{{2049,1,1},{3,2,52}}},
-%%   vendor => "EMQ Technologies Co., Ltd.",
-%%   version => "5.0.0-alpha.1-22e2ad1c"}
-
-parse(Contents, _PublicKey) ->
-    case decode_and_verify_signature(Contents) of
-        {ok, DerCert} ->
-            parse_payload(DerCert);
-        {error, Error} ->
-            {error, Error}
-    end.
-
-dump(#{
-    customer := Customer,
-    email := Email,
-    permits :=
-        #{
-            customer_type := CustomerType,
-            max_connections := MaxConnections,
-            type := Type
-        },
-    validity := {{StartAtDate, _StartAtTime}, {ExpiryAtDate, _ExpiryAtTime}}
-}) ->
-    {DateNow, _} = calendar:universal_time(),
-    Expiry = DateNow > ExpiryAtDate,
-    [
-        {customer, Customer},
-        {email, Email},
-        {deployment, "default"},
-        {max_connections, MaxConnections},
-        {start_at, format_date(StartAtDate)},
-        {expiry_at, format_date(ExpiryAtDate)},
-        {type, format_type(Type)},
-        {customer_type, CustomerType},
-        {expiry, Expiry}
-    ].
-
-customer_type(#{permits := Permits}) ->
-    maps:get(customer_type, Permits, ?LARGE_CUSTOMER).
-
-license_type(#{permits := Permits}) ->
-    maps:get(type, Permits, ?TRIAL).
-
-expiry_date(#{validity := {_From, {EndDate, _EndTime}}}) ->
-    EndDate.
-
-max_connections(#{permits := Permits}) ->
-    maps:get(max_connections, Permits, 0).
-
-%%--------------------------------------------------------------------
-%% Internal functions
-%%--------------------------------------------------------------------
-
-decode_and_verify_signature(Contents) ->
-    try
-        {ok, Cert, DerCert} = decode_license(Contents),
-        [{'Certificate', DerCaCert, _}] = public_key:pem_decode(?CACERT),
-        CaCert = public_key:pkix_decode_cert(DerCaCert, otp),
-        Result = public_key:pkix_path_validation(
-            CaCert,
-            [DerCert],
-            [{verify_fun, {fun verify_fun/3, user_state}}]
-        ),
-        case Result of
-            {ok, _Info} ->
-                {ok, Cert};
-            {error, {bad_cert, Reason}} ->
-                {error, Reason}
-        end
-    catch
-        throw:bad_license_format ->
-            {error, bad_license_format};
-        _:_ ->
-            {error, bad_certificate}
-    end.
-
-decode_license(Contents) ->
-    case public_key:pem_decode(Contents) of
-        [{'Certificate', DerCert, _}] ->
-            Cert = public_key:pkix_decode_cert(DerCert, otp),
-            {ok, Cert, DerCert};
-        _ ->
-            throw(bad_license_format)
-    end.
-
-parse_payload(DerCert) ->
-    try
-        {Start, End} = read_validity(DerCert),
-        Subject = read_subject(DerCert),
-        Permits = read_permits(DerCert),
-        LicenseData = maps:merge(
-            #{
-                vendor => "EMQ Technologies Co., Ltd.",
-                product => emqx_sys:sysdescr(),
-                version => emqx_sys:version(),
-                validity => {Start, End},
-                permits => Permits
-            },
-            Subject
-        ),
-        {ok, LicenseData}
-    catch
-        _:_ ->
-            {error, bad_license}
-    end.
-
-read_validity(#'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{validity = Validity}}) ->
-    case Validity of
-        {'Validity', {utcTime, Start0}, {utcTime, End0}} ->
-            {local_time(Start0), local_time(End0)};
-        {'Validity', {utcTime, Start0}, {generalTime, End0}} ->
-            {local_time(Start0), local_time(End0)}
-    end.
-
-local_time([Y01, Y0, Y1, Y2, M1, M2, D1, D2, H1, H2, Min1, Min2, S1, S2, $Z]) ->
-    {{b2l(<<Y01, Y0, Y1, Y2>>), b2l(<<M1, M2>>), b2l(<<D1, D2>>)}, {
-        b2l(<<H1, H2>>), b2l(<<Min1, Min2>>), b2l(<<S1, S2>>)
-    }};
-local_time([Y1, Y2, M1, M2, D1, D2, H1, H2, Min1, Min2, S1, S2, $Z]) ->
-    {{b2l(<<"20", Y1, Y2>>), b2l(<<M1, M2>>), b2l(<<D1, D2>>)}, {
-        b2l(<<H1, H2>>), b2l(<<Min1, Min2>>), b2l(<<S1, S2>>)
-    }}.
-
-b2l(L) -> binary_to_integer(L).
-
-read_subject(#'OTPCertificate'{tbsCertificate = TbsCertificate}) ->
-    #'OTPTBSCertificate'{subject = {rdnSequence, RDNs}} = TbsCertificate,
-    read_subject(lists:flatten(RDNs), #{}).
-
-read_subject([], Subject) ->
-    Subject;
-read_subject([#'AttributeTypeAndValue'{type = {2, 5, 4, 3}, value = V0} | RDNs], Subject) ->
-    V = unwrap_utf8_string(V0),
-    read_subject(RDNs, maps:put(customer, V, Subject));
-read_subject([#'AttributeTypeAndValue'{type = {2, 5, 4, 10}, value = V0} | RDNs], Subject) ->
-    V = unwrap_utf8_string(V0),
-    read_subject(RDNs, maps:put(customer, V, Subject));
-read_subject(
-    [#'AttributeTypeAndValue'{type = {1, 2, 840, 113549, 1, 9, 1}, value = V} | RDNs],
-    Subject
-) ->
-    read_subject(RDNs, maps:put(email, V, Subject));
-read_subject([_ | RDNs], Subject) ->
-    read_subject(RDNs, Subject).
-
-read_permits(#'OTPCertificate'{tbsCertificate = #'OTPTBSCertificate'{extensions = Extensions}}) ->
-    read_permits(Extensions, #{}).
-
-read_permits([], Permits) ->
-    Permits;
-read_permits(
-    [#'Extension'{extnID = {1, 3, 6, 1, 4, 1, 52509, 1}, extnValue = Val} | More], Permits
-) ->
-    MaxConns = list_to_integer(parse_utf8_string(Val)),
-    read_permits(More, maps:put(max_connections, MaxConns, Permits));
-read_permits(
-    [#'Extension'{extnID = {1, 3, 6, 1, 4, 1, 52509, 2}, extnValue = Val} | More], Permits
-) ->
-    Plugins = [list_to_atom(Plugin) || Plugin <- string:tokens(parse_utf8_string(Val), ",")],
-    read_permits(More, maps:put(enabled_plugins, Plugins, Permits));
-read_permits(
-    [#'Extension'{extnID = {1, 3, 6, 1, 4, 1, 52509, 3}, extnValue = Val} | More], Permits
-) ->
-    Type = list_to_integer(parse_utf8_string(Val)),
-    read_permits(More, maps:put(type, Type, Permits));
-read_permits(
-    [#'Extension'{extnID = {1, 3, 6, 1, 4, 1, 52509, 4}, extnValue = Val} | More], Permits
-) ->
-    CustomerType = list_to_integer(parse_utf8_string(Val)),
-    read_permits(More, maps:put(customer_type, CustomerType, Permits));
-read_permits([_ | More], Permits) ->
-    read_permits(More, Permits).
-
-unwrap_utf8_string({utf8String, Str}) -> Str;
-unwrap_utf8_string(Str) -> Str.
-
-parse_utf8_string(Val) ->
-    {utf8String, Str} = public_key:der_decode('DisplayText', Val),
-    binary_to_list(Str).
-
-format_date({Year, Month, Day}) ->
-    iolist_to_binary(
-        io_lib:format(
-            "~4..0w-~2..0w-~2..0w",
-            [Year, Month, Day]
-        )
-    ).
-
-format_type(?OFFICIAL) -> <<"official">>;
-format_type(?TRIAL) -> <<"trial">>.
-
-%% We want to issue new CA certificates with different issuer and keep
-%% validating old licenses.
-verify_fun(_OTPCertificate, {bad_cert, invalid_issuer}, UserState) ->
-    {valid, UserState};
-%% We want to continue using the same CA certificate even after it
-%% expires.
-verify_fun(_OTPCertificate, {bad_cert, cert_expired}, UserState) ->
-    {valid, UserState};
-verify_fun(OTPCertificate, Event, State) ->
-    DefaultVerifyFun = element(1, ?DEFAULT_VERIFYFUN),
-    DefaultVerifyFun(OTPCertificate, Event, State).

+ 20 - 55
lib-ee/emqx_license/src/emqx_license_schema.erl

@@ -16,16 +16,15 @@
 -export([roots/0, fields/1, validations/0, desc/1]).
 
 -export([
-    license_type/0,
-    key_license/0,
-    file_license/0
+    default_license/0,
+    key_license/0
 ]).
 
 roots() ->
     [
         {license,
             hoconsc:mk(
-                license_type(),
+                key_license(),
                 #{
                     desc => ?DESC(license_root)
                 }
@@ -34,55 +33,14 @@ roots() ->
 
 fields(key_license) ->
     [
-        {type, #{
-            type => key,
-            required => true,
-            desc => ?DESC(license_type_field)
-        }},
         {key, #{
             type => string(),
+            default => default_license(),
             %% so it's not logged
             sensitive => true,
             required => true,
             desc => ?DESC(key_field)
         }},
-        {file, #{
-            type => string(),
-            required => false,
-            desc => ?DESC(file_field)
-        }}
-        | common_fields()
-    ];
-fields(file_license) ->
-    [
-        {type, #{
-            type => file,
-            required => true,
-            desc => ?DESC(license_type_field)
-        }},
-        {key, #{
-            type => string(),
-            %% so it's not logged
-            sensitive => true,
-            required => false,
-            desc => ?DESC(key_field)
-        }},
-        {file, #{
-            type => string(),
-            desc => ?DESC(file_field)
-        }}
-        | common_fields()
-    ].
-
-desc(key_license) ->
-    "License provisioned as a string.";
-desc(file_license) ->
-    "License provisioned as a file.";
-desc(_) ->
-    undefined.
-
-common_fields() ->
-    [
         {connection_low_watermark, #{
             type => emqx_schema:percent(),
             default => "75%",
@@ -95,21 +53,17 @@ common_fields() ->
         }}
     ].
 
+desc(key_license) ->
+    "License provisioned as a string.";
+desc(_) ->
+    undefined.
+
 validations() ->
     [{check_license_watermark, fun check_license_watermark/1}].
 
-license_type() ->
-    hoconsc:union([
-        key_license(),
-        file_license()
-    ]).
-
 key_license() ->
     hoconsc:ref(?MODULE, key_license).
 
-file_license() ->
-    hoconsc:ref(?MODULE, file_license).
-
 check_license_watermark(Conf) ->
     case hocon_maps:get("license.connection_low_watermark", Conf) of
         undefined ->
@@ -121,3 +75,14 @@ check_license_watermark(Conf) ->
                 false -> {bad_license_watermark, #{high => High, low => Low}}
             end
     end.
+
+%% @doc The default license key.
+%% This default license has 1000 connections limit.
+%% It is issued on 2022-04-19 and valid for 5 years (1825 days)
+%% NOTE: when updating a new key, the schema doc in emqx_license_schema_i18n.conf
+%% should be updated accordingly
+default_license() ->
+    "MjIwMTExCjAKMTAKRXZhbHVhdGlvbgpjb250YWN0QGVtcXguaW8KZ"
+    "GVmYXVsdAoyMDIyMDQxOQoxODI1CjEwMDAK.MEQCICbgRVijCQov2"
+    "hrvZXR1mk9Oa+tyV1F5oJ6iOZeSHjnQAiB9dUiVeaZekDOjztk+NC"
+    "Wjhk4PG8tWfw2uFZWruSzD6g==".

+ 2 - 7
lib-ee/emqx_license/src/proto/emqx_license_proto_v2.erl

@@ -11,20 +11,15 @@
 -export([introduced_in/0]).
 
 -export([
-    remote_connection_counts/1,
-    save_and_backup_license/2
+    remote_connection_counts/1
 ]).
 
 -define(TIMEOUT, 500).
 -define(BACKUP_TIMEOUT, 15_000).
 
 introduced_in() ->
-    "5.0.5".
+    "e5.0.0".
 
 -spec remote_connection_counts(list(node())) -> list({atom(), term()}).
 remote_connection_counts(Nodes) ->
     erpc:multicall(Nodes, emqx_license_resources, local_connection_count, [], ?TIMEOUT).
-
--spec save_and_backup_license(list(node()), binary()) -> list({atom(), term()}).
-save_and_backup_license(Nodes, NewLicenseKey) ->
-    erpc:multicall(Nodes, emqx_license, save_and_backup_license, [NewLicenseKey], ?BACKUP_TIMEOUT).

+ 3 - 305
lib-ee/emqx_license/test/emqx_license_SUITE.erl

@@ -27,168 +27,31 @@ end_per_suite(_) ->
 
 init_per_testcase(Case, Config) ->
     {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
-    set_invalid_license_file(Case),
     Paths = set_override_paths(Case),
     Config0 = setup_test(Case, Config),
     Paths ++ Config0 ++ Config.
 
 end_per_testcase(Case, Config) ->
-    restore_valid_license_file(Case),
     clean_overrides(Case, Config),
     teardown_test(Case, Config),
     ok.
 
-set_override_paths(TestCase) when
-    TestCase =:= t_change_from_file_to_key;
-    TestCase =:= t_change_from_key_to_file
-->
-    LocalOverridePath = filename:join([
-        "/tmp",
-        "local-" ++ atom_to_list(TestCase) ++ ".conf"
-    ]),
-    ClusterOverridePath = filename:join([
-        "/tmp",
-        "local-" ++ atom_to_list(TestCase) ++ ".conf"
-    ]),
-    application:set_env(emqx, local_override_conf_file, LocalOverridePath),
-    application:set_env(emqx, cluster_override_conf_file, ClusterOverridePath),
-    [
-        {local_override_path, LocalOverridePath},
-        {cluster_override_path, ClusterOverridePath}
-    ];
 set_override_paths(_TestCase) ->
     [].
 
-clean_overrides(TestCase, Config) when
-    TestCase =:= t_change_from_file_to_key;
-    TestCase =:= t_change_from_key_to_file
-->
-    LocalOverridePath = ?config(local_override_path, Config),
-    ClusterOverridePath = ?config(cluster_override_path, Config),
-    file:delete(LocalOverridePath),
-    file:delete(ClusterOverridePath),
-    application:unset_env(emqx, local_override_conf_file),
-    application:unset_env(emqx, cluster_override_conf_file),
-    ok;
 clean_overrides(_TestCase, _Config) ->
     ok.
 
-setup_test(TestCase, Config) when
-    TestCase =:= t_update_file_cluster_backup
-->
-    DataDir = ?config(data_dir, Config),
-    {LicenseKey, _License} = mk_license(
-        [
-            %% license format version
-            "220111",
-            %% license type
-            "0",
-            %% customer type
-            "10",
-            %% customer name
-            "Foo",
-            %% customer email
-            "contact@foo.com",
-            %% deplayment name
-            "bar-deployment",
-            %% start date
-            "20220111",
-            %% days
-            "100000",
-            %% max connections
-            "19"
-        ]
-    ),
-    Cluster = emqx_common_test_helpers:emqx_cluster(
-        [core, core],
-        [
-            {apps, [emqx_conf, emqx_license]},
-            {load_schema, false},
-            {schema_mod, emqx_enterprise_conf_schema},
-            {env_handler, fun
-                (emqx) ->
-                    emqx_config:save_schema_mod_and_names(emqx_enterprise_conf_schema),
-                    %% emqx_config:save_schema_mod_and_names(emqx_license_schema),
-                    application:set_env(emqx, boot_modules, []),
-                    application:set_env(
-                        emqx,
-                        data_dir,
-                        filename:join([
-                            DataDir,
-                            TestCase,
-                            node()
-                        ])
-                    ),
-                    ok;
-                (emqx_conf) ->
-                    emqx_config:save_schema_mod_and_names(emqx_enterprise_conf_schema),
-                    %% emqx_config:save_schema_mod_and_names(emqx_license_schema),
-                    application:set_env(
-                        emqx,
-                        data_dir,
-                        filename:join([
-                            DataDir,
-                            TestCase,
-                            node()
-                        ])
-                    ),
-                    ok;
-                (emqx_license) ->
-                    LicensePath = filename:join(emqx_license:license_dir(), "emqx.lic"),
-                    filelib:ensure_dir(LicensePath),
-                    ok = file:write_file(LicensePath, LicenseKey),
-                    LicConfig = #{type => file, file => LicensePath},
-                    emqx_config:put([license], LicConfig),
-                    RawConfig = #{<<"type">> => file, <<"file">> => LicensePath},
-                    emqx_config:put_raw([<<"license">>], RawConfig),
-                    ok = persistent_term:put(
-                        emqx_license_test_pubkey,
-                        emqx_license_test_lib:public_key_pem()
-                    ),
-                    ok;
-                (_) ->
-                    ok
-            end}
-        ]
-    ),
-    Nodes = [emqx_common_test_helpers:start_slave(Name, Opts) || {Name, Opts} <- Cluster],
-    [{nodes, Nodes}, {cluster, Cluster}, {old_license, LicenseKey}];
 setup_test(_TestCase, _Config) ->
     [].
 
-teardown_test(TestCase, Config) when
-    TestCase =:= t_update_file_cluster_backup
-->
-    Nodes = ?config(nodes, Config),
-    lists:foreach(
-        fun(N) ->
-            LicenseDir = erpc:call(N, emqx_license, license_dir, []),
-            {ok, _} = emqx_common_test_helpers:stop_slave(N),
-            ok = file:del_dir_r(LicenseDir),
-            ok
-        end,
-        Nodes
-    ),
-    ok;
 teardown_test(_TestCase, _Config) ->
     ok.
 
-set_invalid_license_file(t_read_license_from_invalid_file) ->
-    Config = #{type => file, file => "/invalid/file"},
-    emqx_config:put([license], Config);
-set_invalid_license_file(_) ->
-    ok.
-
-restore_valid_license_file(t_read_license_from_invalid_file) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
-    emqx_config:put([license], Config);
-restore_valid_license_file(_) ->
-    ok.
-
 set_special_configs(emqx_license) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
+    Config = #{key => emqx_license_test_lib:default_license()},
     emqx_config:put([license], Config),
-    RawConfig = #{<<"type">> => file, <<"file">> => emqx_license_test_lib:default_license()},
+    RawConfig = #{<<"key">> => emqx_license_test_lib:default_license()},
     emqx_config:put_raw([<<"license">>], RawConfig);
 set_special_configs(_) ->
     ok.
@@ -201,151 +64,19 @@ assert_on_nodes(Nodes, RunFun, CheckFun) ->
 %% Tests
 %%------------------------------------------------------------------------------
 
-t_update_file(_Config) ->
-    ?assertMatch(
-        {error, enoent},
-        emqx_license:update_file("/unknown/path")
-    ),
-
-    ok = file:write_file("license_with_invalid_content.lic", <<"bad license">>),
-    ?assertMatch(
-        {error, [_ | _]},
-        emqx_license:update_file("license_with_invalid_content.lic")
-    ),
-
-    ?assertMatch(
-        {ok, #{}},
-        emqx_license:update_file(emqx_license_test_lib:default_license())
-    ).
-
-t_update_file_cluster_backup(Config) ->
-    OldLicenseKey = ?config(old_license, Config),
-    Nodes = [N1 | _] = ?config(nodes, Config),
-
-    %% update the license file for the cluster
-    {NewLicenseKey, NewDecodedLicense} = mk_license(
-        [
-            %% license format version
-            "220111",
-            %% license type
-            "0",
-            %% customer type
-            "10",
-            %% customer name
-            "Foo",
-            %% customer email
-            "contact@foo.com",
-            %% deplayment name
-            "bar-deployment",
-            %% start date
-            "20220111",
-            %% days
-            "100000",
-            %% max connections
-            "190"
-        ]
-    ),
-    NewLicensePath = "tmp_new_license.lic",
-    ok = file:write_file(NewLicensePath, NewLicenseKey),
-    {ok, _} = erpc:call(N1, emqx_license, update_file, [NewLicensePath]),
-
-    assert_on_nodes(
-        Nodes,
-        fun() ->
-            Conf = emqx_conf:get([license]),
-            emqx_license:read_license(Conf)
-        end,
-        fun({N, Res}) ->
-            ?assertMatch({ok, _}, Res, #{node => N}),
-            {ok, License} = Res,
-            ?assertEqual(NewDecodedLicense, License, #{node => N})
-        end
-    ),
-
-    assert_on_nodes(
-        Nodes,
-        fun() ->
-            LicenseDir = emqx_license:license_dir(),
-            file:list_dir(LicenseDir)
-        end,
-        fun({N, Res}) ->
-            ?assertMatch({ok, _}, Res, #{node => N}),
-            {ok, DirContents} = Res,
-            %% the now current license
-            ?assert(lists:member("emqx.lic", DirContents), #{node => N, dir_contents => DirContents}),
-            %% the backed up old license
-            ?assert(
-                lists:any(
-                    fun
-                        ("emqx.lic." ++ Suffix) -> lists:suffix(".backup", Suffix);
-                        (_) -> false
-                    end,
-                    DirContents
-                ),
-                #{node => N, dir_contents => DirContents}
-            )
-        end
-    ),
-
-    assert_on_nodes(
-        Nodes,
-        fun() ->
-            LicenseDir = emqx_license:license_dir(),
-            {ok, DirContents} = file:list_dir(LicenseDir),
-            [BackupLicensePath0] = [
-                F
-             || "emqx.lic." ++ F <- DirContents, lists:suffix(".backup", F)
-            ],
-            BackupLicensePath = "emqx.lic." ++ BackupLicensePath0,
-            {ok, BackupLicense} = file:read_file(filename:join(LicenseDir, BackupLicensePath)),
-            {ok, NewLicense} = file:read_file(filename:join(LicenseDir, "emqx.lic")),
-            #{
-                backup => BackupLicense,
-                new => NewLicense
-            }
-        end,
-        fun({N, #{backup := BackupLicense, new := NewLicense}}) ->
-            ?assertEqual(OldLicenseKey, BackupLicense, #{node => N}),
-            ?assertEqual(NewLicenseKey, NewLicense, #{node => N})
-        end
-    ),
-
-    %% uploading the same license twice should not generate extra backups.
-    {ok, _} = erpc:call(N1, emqx_license, update_file, [NewLicensePath]),
-
-    assert_on_nodes(
-        Nodes,
-        fun() ->
-            LicenseDir = emqx_license:license_dir(),
-            {ok, DirContents} = file:list_dir(LicenseDir),
-            [F || "emqx.lic." ++ F <- DirContents, lists:suffix(".backup", F)]
-        end,
-        fun({N, Backups}) ->
-            ?assertMatch([_], Backups, #{node => N})
-        end
-    ),
-
-    ok.
-
 t_update_value(_Config) ->
     ?assertMatch(
         {error, [_ | _]},
         emqx_license:update_key("invalid.license")
     ),
 
-    {ok, LicenseValue} = file:read_file(emqx_license_test_lib:default_license()),
+    LicenseValue = emqx_license_test_lib:default_license(),
 
     ?assertMatch(
         {ok, #{}},
         emqx_license:update_key(LicenseValue)
     ).
 
-t_read_license_from_invalid_file(_Config) ->
-    ?assertMatch(
-        {error, enoent},
-        emqx_license:read_license()
-    ).
-
 t_check_exceeded(_Config) ->
     {_, License} = mk_license(
         [
@@ -435,39 +166,6 @@ t_check_not_loaded(_Config) ->
         emqx_license:check(#{}, #{})
     ).
 
-t_change_from_file_to_key(_Config) ->
-    %% precondition
-    ?assertMatch(#{file := _}, emqx_conf:get([license])),
-
-    OldConf = emqx_conf:get_raw([]),
-
-    %% this saves updated config to `{cluster,local}-overrrides.conf'
-    {ok, LicenseValue} = file:read_file(emqx_license_test_lib:default_license()),
-    {ok, _NewConf} = emqx_license:update_key(LicenseValue),
-
-    %% assert that `{cluster,local}-overrides.conf' merge correctly
-    ?assertEqual(ok, emqx_config:init_load(emqx_license_schema, OldConf, #{})),
-
-    ok.
-
-t_change_from_key_to_file(_Config) ->
-    Config = #{type => key, key => <<"some key">>},
-    emqx_config:put([license], Config),
-    RawConfig = #{<<"type">> => key, <<"key">> => <<"some key">>},
-    emqx_config:put_raw([<<"license">>], RawConfig),
-
-    %% precondition
-    ?assertMatch(#{type := key, key := _}, emqx_conf:get([license])),
-    OldConf = emqx_conf:get_raw([]),
-
-    %% this saves updated config to `{cluster,local}-overrrides.conf'
-    {ok, _NewConf} = emqx_license:update_file(emqx_license_test_lib:default_license()),
-
-    %% assert that `{cluster,local}-overrides.conf' merge correctly
-    ?assertEqual(ok, emqx_config:init_load(emqx_license_schema, OldConf, #{})),
-
-    ok.
-
 %%------------------------------------------------------------------------------
 %% Helpers
 %%------------------------------------------------------------------------------

+ 1 - 1
lib-ee/emqx_license/test/emqx_license_checker_SUITE.erl

@@ -35,7 +35,7 @@ end_per_testcase(_Case, _Config) ->
     ok.
 
 set_special_configs(emqx_license) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
+    Config = #{key => emqx_license_test_lib:default_license()},
     emqx_config:put([license], Config);
 set_special_configs(_) ->
     ok.

+ 3 - 8
lib-ee/emqx_license/test/emqx_license_cli_SUITE.erl

@@ -31,9 +31,9 @@ end_per_testcase(_Case, _Config) ->
     ok.
 
 set_special_configs(emqx_license) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
+    Config = #{key => emqx_license_test_lib:default_license()},
     emqx_config:put([license], Config),
-    RawConfig = #{<<"type">> => file, <<"file">> => emqx_license_test_lib:default_license()},
+    RawConfig = #{<<"key">> => emqx_license_test_lib:default_license()},
     emqx_config:put_raw([<<"license">>], RawConfig);
 set_special_configs(_) ->
     ok.
@@ -48,13 +48,8 @@ t_help(_Config) ->
 t_info(_Config) ->
     _ = emqx_license_cli:license(["info"]).
 
-t_reload(_Config) ->
-    _ = emqx_license_cli:license(["reload", "/invalid/path"]),
-    _ = emqx_license_cli:license(["reload", emqx_license_test_lib:default_license()]),
-    _ = emqx_license_cli:license(["reload"]).
-
 t_update(_Config) ->
-    {ok, LicenseValue} = file:read_file(emqx_license_test_lib:default_license()),
+    LicenseValue = emqx_license_test_lib:default_license(),
     _ = emqx_license_cli:license(["update", LicenseValue]),
     _ = emqx_license_cli:license(["reload"]),
     _ = emqx_license_cli:license(["update", "Invalid License Value"]).

+ 8 - 78
lib-ee/emqx_license/test/emqx_license_http_api_SUITE.erl

@@ -26,9 +26,10 @@ init_per_suite(Config) ->
 
 end_per_suite(_) ->
     emqx_common_test_helpers:stop_apps([emqx_license, emqx_dashboard]),
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
+    LicenseKey = emqx_license_test_lib:make_license(#{max_connections => "100"}),
+    Config = #{key => LicenseKey},
     emqx_config:put([license], Config),
-    RawConfig = #{<<"type">> => file, <<"file">> => emqx_license_test_lib:default_license()},
+    RawConfig = #{<<"key">> => LicenseKey},
     emqx_config:put_raw([<<"license">>], RawConfig),
     persistent_term:erase(emqx_license_test_pubkey),
     ok.
@@ -37,9 +38,9 @@ set_special_configs(emqx_dashboard) ->
     emqx_dashboard_api_test_helpers:set_default_config(<<"license_admin">>);
 set_special_configs(emqx_license) ->
     LicenseKey = emqx_license_test_lib:make_license(#{max_connections => "100"}),
-    Config = #{type => key, key => LicenseKey},
+    Config = #{key => LicenseKey},
     emqx_config:put([license], Config),
-    RawConfig = #{<<"type">> => key, <<"key">> => LicenseKey},
+    RawConfig = #{<<"key">> => LicenseKey},
     emqx_config:put_raw([<<"license">>], RawConfig),
     ok = persistent_term:put(
         emqx_license_test_pubkey,
@@ -82,14 +83,6 @@ assert_untouched_license() ->
         get_license()
     ).
 
-multipart_formdata_request(Uri, File) ->
-    emqx_dashboard_api_test_helpers:multipart_formdata_request(
-        Uri,
-        _Username = <<"license_admin">>,
-        _Fields = [],
-        [File]
-    ).
-
 %%------------------------------------------------------------------------------
 %% Testcases
 %%------------------------------------------------------------------------------
@@ -114,74 +107,11 @@ t_license_info(_Config) ->
     ),
     ok.
 
-t_license_upload_file_success(_Config) ->
-    NewKey = emqx_license_test_lib:make_license(#{max_connections => "999"}),
-    Res = multipart_formdata_request(
-        uri(["license", "file"]),
-        {filename, "emqx.lic", NewKey}
-    ),
-    ?assertMatch({ok, 200, _}, Res),
-    {ok, 200, Payload} = Res,
-    ?assertEqual(
-        #{
-            <<"customer">> => <<"Foo">>,
-            <<"customer_type">> => 10,
-            <<"deployment">> => <<"bar-deployment">>,
-            <<"email">> => <<"contact@foo.com">>,
-            <<"expiry">> => false,
-            <<"expiry_at">> => <<"2295-10-27">>,
-            <<"max_connections">> => 999,
-            <<"start_at">> => <<"2022-01-11">>,
-            <<"type">> => <<"trial">>
-        },
-        emqx_json:decode(Payload, [return_maps])
-    ),
-    ?assertMatch(
-        #{max_connections := 999},
-        get_license()
-    ),
-    ok.
-
-t_license_upload_file_bad_license(_Config) ->
-    Res = multipart_formdata_request(
-        uri(["license", "file"]),
-        {filename, "bad.lic", <<"bad key">>}
-    ),
-    ?assertMatch({ok, 400, _}, Res),
-    {ok, 400, Payload} = Res,
-    ?assertEqual(
-        #{
-            <<"code">> => <<"BAD_REQUEST">>,
-            <<"message">> => <<"Bad license file">>
-        },
-        emqx_json:decode(Payload, [return_maps])
-    ),
-    assert_untouched_license(),
-    ok.
-
-t_license_upload_file_not_json(_Config) ->
-    Res = request(
-        post,
-        uri(["license", "file"]),
-        <<"">>
-    ),
-    ?assertMatch({ok, 400, _}, Res),
-    {ok, 400, Payload} = Res,
-    ?assertEqual(
-        #{
-            <<"code">> => <<"BAD_REQUEST">>,
-            <<"message">> => <<"Invalid request params">>
-        },
-        emqx_json:decode(Payload, [return_maps])
-    ),
-    assert_untouched_license(),
-    ok.
-
 t_license_upload_key_success(_Config) ->
     NewKey = emqx_license_test_lib:make_license(#{max_connections => "999"}),
     Res = request(
         post,
-        uri(["license", "key"]),
+        uri(["license"]),
         #{key => NewKey}
     ),
     ?assertMatch({ok, 200, _}, Res),
@@ -210,7 +140,7 @@ t_license_upload_key_bad_key(_Config) ->
     BadKey = <<"bad key">>,
     Res = request(
         post,
-        uri(["license", "key"]),
+        uri(["license"]),
         #{key => BadKey}
     ),
     ?assertMatch({ok, 400, _}, Res),
@@ -228,7 +158,7 @@ t_license_upload_key_bad_key(_Config) ->
 t_license_upload_key_not_json(_Config) ->
     Res = request(
         post,
-        uri(["license", "key"]),
+        uri(["license"]),
         <<"">>
     ),
     ?assertMatch({ok, 400, _}, Res),

+ 1 - 1
lib-ee/emqx_license/test/emqx_license_installer_SUITE.erl

@@ -31,7 +31,7 @@ end_per_testcase(_Case, _Config) ->
     ok.
 
 set_special_configs(emqx_license) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
+    Config = #{key => emqx_license_test_lib:default_license()},
     emqx_config:put([license], Config);
 set_special_configs(_) ->
     ok.

+ 1 - 1
lib-ee/emqx_license/test/emqx_license_parser_SUITE.erl

@@ -30,7 +30,7 @@ end_per_testcase(_Case, _Config) ->
     ok.
 
 set_special_configs(emqx_license) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
+    Config = #{key => emqx_license_test_lib:default_license()},
     emqx_config:put([license], Config);
 set_special_configs(_) ->
     ok.

+ 0 - 114
lib-ee/emqx_license/test/emqx_license_parser_legacy_SUITE.erl

@@ -1,114 +0,0 @@
-%%--------------------------------------------------------------------
-%% Copyright (c) 2022 EMQ Technologies Co., Ltd. All Rights Reserved.
-%%--------------------------------------------------------------------
-
--module(emqx_license_parser_legacy_SUITE).
-
--compile(nowarn_export_all).
--compile(export_all).
-
--include_lib("eunit/include/eunit.hrl").
--include_lib("public_key/include/public_key.hrl").
-
-all() ->
-    emqx_common_test_helpers:all(?MODULE).
-
-init_per_suite(Config) ->
-    _ = application:load(emqx_conf),
-    emqx_common_test_helpers:start_apps([emqx_license], fun set_special_configs/1),
-    Config.
-
-end_per_suite(_) ->
-    emqx_common_test_helpers:stop_apps([emqx_license]),
-    ok.
-
-init_per_testcase(_Case, Config) ->
-    {ok, _} = emqx_cluster_rpc:start_link(node(), emqx_cluster_rpc, 1000),
-    Config.
-
-end_per_testcase(_Case, _Config) ->
-    ok.
-
-set_special_configs(emqx_license) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
-    emqx_config:put([license], Config);
-set_special_configs(_) ->
-    ok.
-
-%%------------------------------------------------------------------------------
-%% Tests - emqx_license_parser API
-%%------------------------------------------------------------------------------
-
-t_parse(_Config) ->
-    ?assertMatch({ok, _}, emqx_license_parser:parse(sample_license(), public_key_pem())),
-
-    Res1 = emqx_license_parser:parse(tampered_license(), public_key_pem()),
-    ?assertMatch({error, _}, Res1),
-    {error, Errors} = Res1,
-    ?assertEqual(
-        invalid_signature,
-        proplists:get_value(emqx_license_parser_legacy, Errors)
-    ),
-
-    ok.
-
-t_dump(_Config) ->
-    {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()),
-    ?assertEqual(
-        [
-            {customer, <<"EMQ X Evaluation">>},
-            {email, "contact@emqx.io"},
-            {deployment, "default"},
-            {max_connections, 10},
-            {start_at, <<"2020-06-20">>},
-            {expiry_at, <<"2049-01-01">>},
-            {type, <<"official">>},
-            {customer_type, 10},
-            {expiry, false}
-        ],
-        emqx_license_parser:dump(License)
-    ).
-
-t_customer_type(_Config) ->
-    {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()),
-    ?assertEqual(10, emqx_license_parser:customer_type(License)).
-
-t_license_type(_Config) ->
-    {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()),
-    ?assertEqual(1, emqx_license_parser:license_type(License)).
-
-t_max_connections(_Config) ->
-    {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()),
-    ?assertEqual(10, emqx_license_parser:max_connections(License)).
-
-t_expiry_date(_Config) ->
-    {ok, License} = emqx_license_parser:parse(sample_license(), public_key_pem()),
-    ?assertEqual({2049, 1, 1}, emqx_license_parser:expiry_date(License)).
-
-%%------------------------------------------------------------------------------
-%% Helpers
-%%------------------------------------------------------------------------------
-
-%% not used for this parser, but required for the behaviour.
-public_key_pem() ->
-    emqx_license_test_lib:public_key_pem().
-
-sample_license() ->
-    emqx_license_test_lib:legacy_license().
-
-tampered_license() ->
-    LicenseBin = emqx_license_test_lib:legacy_license(),
-    [{'Certificate', DerCert, _}] = public_key:pem_decode(LicenseBin),
-    Cert = public_key:pkix_decode_cert(DerCert, otp),
-    TbsCert = Cert#'OTPCertificate'.tbsCertificate,
-    Validity0 = TbsCert#'OTPTBSCertificate'.validity,
-    Validity = Validity0#'Validity'{notBefore = {utcTime, "19800620030252Z"}},
-
-    TamperedCert = Cert#'OTPCertificate'{
-        tbsCertificate =
-            TbsCert#'OTPTBSCertificate'{
-                validity = Validity
-            }
-    },
-    TamperedCertDer = public_key:pkix_encode('OTPCertificate', TamperedCert, otp),
-    public_key:pem_encode([{'Certificate', TamperedCertDer, not_encrypted}]).

+ 1 - 1
lib-ee/emqx_license/test/emqx_license_resources_SUITE.erl

@@ -31,7 +31,7 @@ end_per_testcase(_Case, _Config) ->
     ok.
 
 set_special_configs(emqx_license) ->
-    Config = #{type => file, file => emqx_license_test_lib:default_license()},
+    Config = #{key => emqx_license_test_lib:default_license()},
     emqx_config:put([license], Config);
 set_special_configs(_) ->
     ok.

+ 1 - 11
lib-ee/emqx_license/test/emqx_license_test_lib.erl

@@ -18,8 +18,6 @@
     "10"
 ]).
 
--define(DEFAULT_LICENSE_FILE, "emqx.lic").
-
 private_key() ->
     test_key("pvt.key").
 
@@ -32,9 +30,6 @@ public_key_pem() ->
 test_key(Filename) ->
     test_key(Filename, decoded).
 
-legacy_license() ->
-    test_key("emqx.lic", pem).
-
 test_key(Filename, Format) ->
     Dir = code:lib_dir(emqx_license, test),
     Path = filename:join([Dir, "data", Filename]),
@@ -82,9 +77,4 @@ make_license(Values) ->
     iolist_to_binary([EncodedText, ".", EncodedSignature]).
 
 default_license() ->
-    %% keep it the same as in etc/emqx_license.conf
-    License =
-        "MjIwMTExCjAKMTAKRXZhbHVhdGlvbgpjb250YWN0QGVtcXguaW8KZGVmYXVsdAoyMDIyMDQxOQoxODI1CjEwMDAK."
-        "MEQCICbgRVijCQov2hrvZXR1mk9Oa+tyV1F5oJ6iOZeSHjnQAiB9dUiVeaZekDOjztk+NCWjhk4PG8tWfw2uFZWruSzD6g==",
-    ok = file:write_file(?DEFAULT_LICENSE_FILE, License),
-    ?DEFAULT_LICENSE_FILE.
+    emqx_license_schema:default_license().