草庐IT

OpenHarmony解读之设备认证:pake协议-客户端发起start请求

xjingxuan 2023-04-09 原文

一、概述

在设备认证过程中,pake协议用于认证会话密钥协商,基于该会话密钥,双方可以安全地交换各自的身份公钥。从本文开始,将对pake协议的详细过程进行介绍,本博客主要介绍客户端发起start请求的过程,协议状态从PROTOCOL_INIT转换为START_REQUEST。

二、源码分析

这一模块的源码位于:/base/security/deviceauth。

1. start_pake函数,启动pake模块。
/*
函数功能:启动pake模块
函数参数:
    handle:hichain实例
    params:操作参数
函数返回值:
    成功:0
    失败:error
*/
DLL_API_PUBLIC int32_t start_pake(hc_handle handle, const struct operation_parameter *params)
{
    LOGI("Begin start pake");
    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性
    check_ptr_return_val(params, HC_INPUT_ERROR);
    struct hichain *hichain = (struct hichain *)handle;//获取hichain实例

    int32_t ret = build_object(hichain, PAKE_MODULAR, true, params);//构建PAKE_MODULAR client子对象
    if (ret != HC_OK) {
        LOGE("Build pake client sub object failed, error code is %d", ret);
        return ret;
    }

    ret = triggered_pake_client(hichain, BIND);//触发pake client子对象,发起设备绑定
    LOGI("Triggered pake client error code is %d", ret);
    LOGI("End start pake");
    return ret;
}
2. 首先调用build_object函数构建pake客户端对象。
/*
函数功能:构建HiChain子对象
函数参数:
    hichain:HiChain实例
    modular:消息模块类型
    is_client:是否是client
    params:构建参数
函数返回值:
    成功:返回0 HC_OK
    失败:返回错误码
详细:
*/
int32_t build_object(struct hichain *hichain, int32_t modular, bool is_client, const void *params)
{
    //初始化HC对象表map
    const struct object_map map[] = { { PAKE_MODULAR, true, (void **)&hichain->pake_client },//pake客户端
                                      { PAKE_MODULAR, false, (void **)&hichain->pake_server },//pake服务端
                                      { STS_MODULAR, true, (void **)&hichain->sts_client },//sts客户端
                                      { STS_MODULAR, false, (void **)&hichain->sts_server },//sts服务端
                                      { ADD_MODULAR, true, (void **)&hichain->auth_info },//认证信息
                                      { REMOVE_MODULAR, true, (void **)&hichain->auth_info },//认证信息
                                      { SEC_CLONE_MODULAR, false, (void **)&hichain->sec_clone_server } };//安全克隆服务端
    void **object = get_object(map, sizeof(map) / sizeof(map[0]), modular, is_client);//根据消息模块类型获取HC对象
    if ((object == NULL) || (*object != NULL)) {//获取失败
        DBG_OUT("No sub-objects need to be applied for");
        return HC_OK;
    }
    if (check_mutex_object_is_null(map, sizeof(map) / sizeof(map[0]), modular, is_client) == false) {//检查互斥对象是否为空
        LOGE("The mutex sub-object have been created, create %d:%d sub-object failed", modular, is_client);
        return HC_REPEATED_REFERENCE;
    }
    if (check_depend_object_is_not_null(map, sizeof(map) / sizeof(map[0]), modular, is_client) == false) {//检查依赖对象是否为非空
        LOGE("The depend sub-object is not created, create %d:%d sub-object failed", modular, is_client);
        return HC_NEED_DEPEND;
    }
    *object = build_object_by_modular(hichain, modular, is_client, params);//根据消息模块协议类型构建子对象
    if (*object == NULL) {
        LOGE("Create %d:%d sub-object failed", modular, is_client);
        return HC_BUILD_OBJECT_FAILED;//构建失败
    }
    DBG_OUT("Create %d:%d sub-object success", modular, is_client);
    return HC_OK;
}
3. 实际上最终是执行build_pake_client_object函数构建客户端对象。
/*
函数功能:构建pake协议客户端对象
函数参数:
    hichain:hichain实例
    params:参数
函数返回值:
    成功:子对象首地址
    失败:NULL
*/
static void *build_pake_client_object(struct hichain *hichain, const void *params)
{
    (void)params;//未使用参数
    struct hc_pin pin = { 0, {0} };
    struct operation_parameter para;//操作参数

    (void)memset_s(&para, sizeof(para), 0, sizeof(para));//清空操作参数空间
    hichain->cb.get_protocol_params(&hichain->identity, hichain->operation_code, &pin, &para);//获取协议参数
    if (check_param_is_valid(&para) == false) {//检查参数是否有效
        LOGE("Param invalid");
        return NULL;
    }
    if (pin.length > HC_PIN_BUFF_LEN) {//检查PIN是否有效
        LOGE("PIN invalid");
        return NULL;
    }
    return build_pake_client(&hichain->identity, &pin, para.key_length, &para.self_auth_id, &para.peer_auth_id);//构建pake客户端对象
}

/*
函数功能:构建pake客户端
函数参数:
    identity:hichain会话标识
    pin:PIN码
    key_length:密钥长度
    client:客户端认证id
    server:服务端认证id
函数返回值:
    成功:struct pake_client地址
    失败:NULL
*/
struct pake_client *build_pake_client(const struct session_identity *identity, const struct hc_pin *pin,
    uint32_t key_length, const struct hc_auth_id *client, const struct hc_auth_id *server)
{
    struct pake_client *pake_client = (struct pake_client *)MALLOC(sizeof(struct pake_client));//为pake客户端对象申请空间
    if (pake_client == NULL) {
        LOGE("Build pake client object failed");
        return NULL;
    }

    (void)memset_s(pake_client, sizeof(*pake_client), 0, sizeof(*pake_client));//清空该空间
    struct client_virtual_func_group funcs = { build_start_request_data, parse_start_response_data,
                                               build_end_request_data, parse_end_response_data };//初始化客户端虚函数组

    init_client(&pake_client->client_info, &funcs);//初始化协议基础信息和协议客户端打包函数为funcs
    pake_client->pin = *pin;//赋值PIN
    pake_client->key_length = key_length;//赋值密钥长度
    pake_client->self_id = *client;//赋值客户端认证id为本端id
    pake_client->peer_id = *server;//赋值服务端认证id为对端id
    pake_client->identity = identity;//赋值会话标识
    pake_client->prime_type = NUM_LEN_384;//最大质数类型
    LOGI("Build pake client object %u success", pake_client_sn(pake_client));

    return pake_client;
}
4. build_start_request_data函数,构造start请求数据。
//构造pake_client start请求数据,data参数:数据地址
static int32_t build_start_request_data(void *handle, void *data)
{
    struct pake_client *pake_client = (struct pake_client *)handle;//接收pake_client对象
    struct pake_start_request_data *send_data = (struct pake_start_request_data *)data;//接收数据地址

    send_data->peer_version.first = 1;//初始化对端版本号
    send_data->peer_version.second = 0;
    send_data->peer_version.third = 0;
    send_data->peer_support_version.first = 1;//初始化对端可支持的版本号
    send_data->peer_support_version.second = 0;
    send_data->peer_support_version.third = 0;
    send_data->operation_code = pake_client->operation_code;//赋值操作码
    send_data->epk_len = HC_BIG_PRIME_MAX_LEN;//企业级公钥长度为最大质数长度

    return HC_OK;
}
5. 回到start_pake函数中,继续执行triggered_pake_client函数,触发pake client子对象,发起设备绑定。
/*
函数功能:触发pake_client子对象
函数参数:
    hichain:hichain实例
    operation_code:操作码
函数返回值:
    成功:0
    失败:error
*/
static int32_t triggered_pake_client(struct hichain *hichain, int32_t operation_code)
#if !(defined(_CUT_PAKE_) || defined(_CUT_PAKE_CLIENT_))
{
    hichain->operation_code = operation_code;//赋值操作码
    hichain->pake_client->operation_code = operation_code;

    struct message send = {//“发送消息”
        .msg_code = PAKE_REQUEST,
        .rsv = 0,
        .payload = NULL
    };
    int32_t ret = send_pake_start_request(hichain->pake_client, &send);//发送pake协议start请求
    if (ret != HC_OK) {
        LOGE("Object %u build sts start request failed, error code is %d", pake_client_sn(hichain->pake_client), ret);
        return HC_BUILD_SEND_DATA_FAILED;
    }

    void *send_data = NULL;
    uint32_t send_data_len = 0;

    ret = build_send_data_by_struct(&send, &send_data, &send_data_len);//构造格式化的客户端请求数据,此处为json格式的字符串
    if (ret != HC_OK) {
        LOGW("build send data failed, error code is %d", ret);
    } else {
        DBG_OUT("send_data:%s", (uint8_t *)send_data);
        hichain->cb.transmit(&hichain->identity, send_data, send_data_len);//调用软总线模块传输数据,消息起始地址为send_data,长度为send_data_len
        FREE(send_data);
    }

    set_result(hichain, INVALID_MESSAGE, PAKE_REQUEST, ret);//根据接收消息码和发送消息码设置hichain结果和状态
    destroy_send_data(&send);//销毁发送缓冲区
    return ret;
}
6. 在triggered_pake_client函数中,首先执行send_pake_start_request函数初始化待发送消息。
/*
函数功能:发送“pake start request”消息
函数参数:
    pake_client:pake客户端对象
    send:待发送消息
函数返回值:
    成功:0
    失败:error
*/
int32_t send_pake_start_request(struct pake_client *pake_client, struct message *send)
{
    check_ptr_return_val(pake_client, HC_INPUT_ERROR);//检查参数有效性
    check_ptr_return_val(send, HC_INPUT_ERROR);
    struct pake_start_request_data *send_data =
        (struct pake_start_request_data *)MALLOC(sizeof(struct pake_start_request_data));//为待发送的请求消息申请内存空间
    if (send_data == NULL) {
        LOGE("Malloc struct PAKE_START_REQUEST_DATA failed");
        return HC_MALLOC_FAILED;
    }
    (void)memset_s(send_data, sizeof(*send_data), 0, sizeof(*send_data));//清空该内存空间

    int32_t ret = send_start_request(pake_client, send_data);//发送start请求
    if (ret != HC_OK) {
        LOGE("Called send_start_request failed, error code is %d", ret);
        FREE(send_data);
        send->msg_code = INFORM_MESSAGE;
    } else {
        DBG_OUT("Called send_start_request success");
        send->msg_code = PAKE_REQUEST;
        send->payload = send_data;
    }

    return ret;
}

/*
函数功能:发送start请求
函数参数:
    handle:句柄
    send_data:待发送数据地址
函数返回值:
    成功:0
    失败:error
*/
int32_t send_start_request(void *handle, void *send_data)
{
    check_ptr_return_val(handle, HC_INPUT_ERROR);//检查参数有效性
    check_ptr_return_val(send_data, HC_INPUT_ERROR);
    struct key_agreement_client *client = (struct key_agreement_client *)handle;//密钥协商客户端
    struct key_agreement_protocol *base = &client->protocol_base_info;//基础密钥协议信息

    DBG_OUT("Object %u begin send start request data", base->sn);
    if (is_state_error(client, SEND_START_REQUEST)) {//判断协议动作和协议状态是否对应错误
        LOGE("Object %u state error", base->sn);
        return PROTOCOL_STATE_ERROR;
    }
    struct client_virtual_func_group *funcs = &client->package_funcs;//赋值虚拟函数群为客户端打包函数
    int32_t ret = funcs->build_start_request_data(handle, send_data);//执行打包函数
    if (ret != HC_OK) {
        set_state(base, PROTOCOL_ERROR);
        LOGE("Object %u build start request data failed, error code is %d", base->sn, ret);
        return ret;
    }
    set_state(base, START_REQUEST);//设置协议新状态为START_REQUEST
    set_last_time_sec(base);//设置上一次的时间
    DBG_OUT("Object %u send start request data success", base->sn);
    return HC_OK;
}

/*
函数功能:设置协议状态
函数参数:
    handle:密钥协商协议句柄
    new_state:新协议状态
函数返回值:无
*/
void set_state(struct key_agreement_protocol *handle, enum protocol_state new_state)
{
    check_ptr_return(handle);//检查参数有效性
    enum protocol_state ori_state = handle->state;//定义原始状态

    DBG_OUT("Object %u state is %u, new state is %u", handle->sn, ori_state, new_state);
    if ((ori_state == PROTOCOL_TIMEOUT) || (ori_state == PROTOCOL_ERROR) || (ori_state == PROTOCOL_FINISH)) {//如果原始状态为"超时"、"错误"、"结束",就直接返回,因为没有下一状态
        LOGE("Object %u state cannot change", handle->sn);
        return; /* not allowed to modify these end status */
    }
    if (new_state < ori_state) {//不允许协议状态回滚
        LOGE("Object %u state cannot rollback", handle->sn);
        return;
    }

    if (handle->state != new_state) {//如果新状态与当前状态不等
        handle->last_state = ori_state;//将原始状态赋给last_state(上一个状态)
        handle->state = new_state;//赋值新状态
    }
}
7. 然后执行build_send_data_by_struct函数,构造格式化的客户端请求数据,此处为json格式的字符串。
/*
函数功能:构造结构化的发送消息
函数参数:
    message:输出参数,消息地址
    send_data:输出参数,消息有效载荷地址
    send_data_len:输出参数,消息有效载荷长度
函数返回值:
    成功:返回0
    失败:返回错误码
*/
static int32_t build_send_data_by_struct(const struct message *message, void **send_data, uint32_t *send_data_len)
{
    //消息构造表
    const struct make_message_map map[] = { { PAKE_REQUEST, make_pake_request },//构造pake请求消息
                                            { PAKE_RESPONSE, make_pake_response },//构造pake响应消息
                                            { PAKE_CLIENT_CONFIRM, make_pake_client_confirm },//构造pake协议客户端认证消息
                                            { PAKE_SERVER_CONFIRM_RESPONSE, make_pake_server_confirm },//构造pake协议服务端认证消息
                                            { AUTH_START_REQUEST, make_auth_start_request },//构造认证开始请求消息
                                            { AUTH_START_RESPONSE, make_auth_start_response },//构造认证开始响应消息
                                            { AUTH_ACK_REQUEST, make_auth_ack_request },//构造认证确认请求消息
                                            { AUTH_ACK_RESPONSE, make_auth_ack_response },//构造认证确认响应消息
                                            { ADD_AUTHINFO_REQUEST, make_add_auth_info_request },//构造添加认证信息请求消息
                                            { REMOVE_AUTHINFO_REQUEST, make_rmv_auth_info_request },//构造移除认证信息请求消息
                                            { ADD_AUTHINFO_RESPONSE, make_add_auth_info_response },//构造添加认证信息响应消息
                                            { REMOVE_AUTHINFO_RESPONSE, make_rmv_auth_info_response },//构造移除认证信息响应消息
                                            { EXCHANGE_REQUEST, make_exchange_request },//构造交换信息请求消息
                                            { EXCHANGE_RESPONSE, make_exchange_response },//构造交换信息响应消息
                                            { SEC_CLONE_START_RESPONSE, sec_clone_make_srv_proof },
                                            { SEC_CLONE_ACK_RESPONSE, sec_clone_make_clone_ret },
                                            { INFORM_MESSAGE, make_inform_message } };//构造通知消息

    if (message->msg_code == INVALID_MESSAGE) {//如果消息码为无效,则返回“无消息发送”
        return HC_NO_MESSAGE_TO_SEND;
    }

    if (message->payload == NULL) {//如果发送负载为空,则返回错误码
        LOGE("Message payload is null");
        return HC_BUILD_SEND_DATA_FAILED;
    }

    for (uint32_t i = 0; i < sizeof(map) / sizeof(struct make_message_map); i++) {//遍历消息构造表
        if (map[i].msg_code != message->msg_code) {
            continue;
        }
        *send_data = map[i].make_message(message->payload);//调用构造消息回调函数!!!
        if (*send_data == NULL) {//构造消息失败
            return HC_BUILD_SEND_DATA_FAILED;
        }
        *send_data_len = strlen(*send_data);//构造消息成功,获取长度
        return HC_OK;
    }

    LOGE("Unsupport encape 0x%04x message", message->msg_code);
    return HC_INNER_ERROR;
}
8. 实际上是执行make_pake_request回调函数构造pake请求消息。
/*
函数功能:构造pake请求消息
函数参数:
    data:数据首地址
函数返回值:返回json格式的字符串
详细:
消息字符串实际为:{"message":1,"payload":{"version":{"currentVersion":"1.0.0","minVersion":"1.0.0"},"support256mod":true,"operationCode":1}}
*/
char *make_pake_request(void *data)
{
    struct pake_start_request_data *pake_request = data;//接收pake_start_request_data结构的数据
    char *ret_str = (char *)MALLOC(RET_STR_LENGTH);//为回复消息申请空间
    if (ret_str == NULL) {
        return NULL;
    }
    (void)memset_s(ret_str, RET_STR_LENGTH, 0, RET_STR_LENGTH);//清空该空间
    if (snprintf_s(ret_str, RET_STR_LENGTH, RET_STR_LENGTH - 1,
        "{\"%s\":%d,\"%s\":{\"%s\":{\"%s\":\"%u.%u.%u\",\"%s\":\"%u.%u.%u\"},\"%s\":true,\"%s\":%d}}",
        FIELD_MESSAGE, PAKE_REQUEST, FIELD_PAYLOAD, FIELD_VERSION, FIELD_CURRENT_VERSION,
        pake_request->peer_version.first, pake_request->peer_version.second,
        pake_request->peer_version.third, FIELD_MIN_VERSION,
        pake_request->peer_support_version.first, pake_request->peer_support_version.second,
        pake_request->peer_support_version.third, FIELD_SUPPORT_256_MOD,
        FIELD_OPERATION_CODE, pake_request->operation_code) < 0) {//生成json格式的字符串作为消息数据
        LOGE("String generate failed");
        FREE(ret_str);
        ret_str = NULL;
    }
    return ret_str;//返回json格式的字符串
}
9. 最后执行set_result函数设置hichain状态和结果。
/*
函数功能:设置最终结果信息,即HiChain状态
函数参数:
    hichain:hichain实例对象
    rcv_msg_code:接收消息码
    snd_msg_code:发送消息码
    error_code:错误码
函数返回值:无
*/
static void set_result(struct hichain *hichain, uint16_t rcv_msg_code, uint16_t snd_msg_code, int32_t error_code)
{
    if (error_code != HC_OK) {//如果错误码不是0,则直接跳转到error,按对应错误码设置结果
        LOGE("Error code is not ok, and set end failed");
        goto error;
    }
    if (snd_msg_code == INFORM_MESSAGE) {//如果发送消息码为通知消息,则直接跳转到error
        LOGE("Send an inform message, and set end failed");
        goto error;
    }
    //消息结果表
    const struct msg_result_map map[] = { { PAKE_REQUEST, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },//密钥协商过程中
                                          { PAKE_RESPONSE, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },//密钥协商过程中
                                          { PAKE_CLIENT_CONFIRM, KEY_AGREEMENT_END, OPERATION_STATE },//密钥协商结束
                                          { PAKE_SERVER_CONFIRM_RESPONSE, KEY_AGREEMENT_END, OPERATION_STATE },//密钥协商结束
                                          { EXCHANGE_REQUEST, END_SUCCESS, OVER_STATE },
                                          { EXCHANGE_RESPONSE, END_SUCCESS, OVER_STATE },
                                          { AUTH_START_REQUEST, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },
                                          { AUTH_START_RESPONSE, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE },
                                          { AUTH_ACK_REQUEST, KEY_AGREEMENT_END, OPERATION_STATE },
                                          { AUTH_ACK_RESPONSE, KEY_AGREEMENT_END, OPERATION_STATE },
                                          { ADD_AUTHINFO_REQUEST, END_SUCCESS, OVER_STATE },
                                          { ADD_AUTHINFO_RESPONSE, END_SUCCESS, OVER_STATE },
                                          { REMOVE_AUTHINFO_REQUEST, END_SUCCESS, OVER_STATE },
                                          { REMOVE_AUTHINFO_RESPONSE, END_SUCCESS, OVER_STATE },
                                          { SEC_CLONE_START_REQUEST, OPERATION_PROCESSING, OPERATION_STATE },
                                          { SEC_CLONE_ACK_REQUEST, END_SUCCESS, OVER_STATE },
                                          { INFORM_MESSAGE, END_FAILED, OVER_STATE },
                                          { INVALID_MESSAGE, KEY_AGREEMENT_PROCESSING, KEY_AGREEMENT_STATE } };
    const struct msg_result_map *map_ptr = select_result_map(rcv_msg_code, map,
        sizeof(map) / sizeof(struct msg_result_map));//根据接收消息码查找结果表

    set_result_by_map(hichain, map_ptr);//根据结果表内容设置最终结果
    return;
error:
    hichain->last_state = hichain->state;//将hc当前状态赋给last_state
    hichain->state = OVER_STATE;//设置hc当前状态为OVER_STATE
    hichain->cb.set_service_result(&hichain->identity, END_FAILED);//调用软总线模块回调函数设置服务结果为END_FAILED!!!
}

三、小结

经过分析,可以得到pake协议的start请求的消息格式为:

{
    "message":1,//消息码为PAKE_REQUEST
    "payload":
    {
        "version":
        {
            "currentVersion":"1.0.0",//当前版本号
            "minVersion":"1.0.0"//最低版本号
        },
        "support256mod":true,//是否支持256mod
        "operationCode":1//操作码为BIND
    }
}

根据消息内容可以知道,客户端发起start请求的目的在于将本端的协议版本号、是否支持256mod、操作码等信息发送给服务端,向服务端发起认证会话密钥协商请求

有关OpenHarmony解读之设备认证:pake协议-客户端发起start请求的更多相关文章

  1. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  2. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  3. ruby-on-rails - 禁用设备的 :confirmable on-the-fly to batch-generate users - 2

    Devise是一个Ruby库,它为我提供了这个User类:classUser当写入:confirmable时,注册时会发送一封确认邮件。上周我不得不批量创建300个用户,所以我在恢复之前注释掉了:confirmable几分钟。现在我正在为用户批量创建创建一个UI,因此我需要即时添加/删除:confirmable。(我也可以直接修改Devise的源码,但我宁愿不去调和它)问题:如何即时添加/删除:confirmable? 最佳答案 WayneConrad的解决方案:user=User.newuser.skip_confirmation

  4. ruby - 在 TCPServer (Ruby) 中,我如何从客户端获取 IP/MAC? - 2

    我想在Ruby的TCPServer中获取客户端的IP地址。以及(如果可能的话)MAC地址。例如,Ruby中的时间服务器,请参阅评论。tcpserver=TCPServer.new("",80)iftcpserverputs"Listening"loopdosocket=tcpserver.acceptifsocketThread.newdoputs"Connectedfrom"+#HERE!HowcanigettheIPAddressfromtheclient?socket.write(Time.now.to_s)socket.closeendendendend非常感谢!

  5. ruby - HTTP POST 上的 SSL 错误(未知协议(protocol)) - 2

    尝试通过SSL连接到ImgurAPI时出现错误。这是代码和错误:API_URI=URI.parse('https://api.imgur.com')API_PUBLIC_KEY='Client-ID--'ENDPOINTS={:image=>'/3/image',:gallery=>'/3/gallery'}#Public:Uploadanimage##args-Theimagepathfortheimagetoupload#defupload(image_path)http=Net::HTTP.new(API_URI.host)http.use_ssl=truehttp.verify

  6. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  7. ruby-on-rails - 为什么我必须在使用客户验证器后重新加载 rspec 中的记录? - 2

    我有一个模型User,它在创建后的回调中创建了选项#Userhas_one:user_optionsafter_create:create_optionsprivatedefcreate_optionsUserOptions.create(user:self)end我对此有一些简单的Rspec覆盖:describe"newuser"doit"createsuser_optionsaftertheuseriscreated"douser=create(:user)user.user_options.shouldbe_kind_of(UserOptions)endend一切正常,直到我将自

  8. ruby - 如何获得带有 SSL 客户端证书的 HTTPS 请求以与 Ruby EventMachine 一起使用? - 2

    我正在尝试使用RubyEventMachine访问使用SSL证书身份验证的HTTPSWeb服务,但我没有让它工作。我编写了以下简单代码块来对其进行端到端测试:require'rubygems'require'em-http'EventMachine.rundourl='https://foobar.com/'ssl_opts={:private_key_file=>'/tmp/private.key',:cert_chain_file=>'/tmp/ca.pem',:verify_peer=>false}http=EventMachine::HttpRequest.new(url).g

  9. Ruby:net/http 可以同时发起 GET 和 POST 请求吗? - 2

    是否可以同时传递GET和POST参数?uri=URI.parse("http://www.example.com/post.php?a=1&b=2")req=Net::HTTP::Post.new(uri.path,{'Referer'=>"http://www.example.com/referer",'User-Agent'=>"Mozilla/4.0(compatible;MSIE7.0;WindowsNT5.1)",'Cookie'=>$cookie})req.set_form_data({'foo'=>'bar','bar'=>'foo'})http=Net::HTTP.ne

  10. ruby-on-rails - 在 Ruby on Rails 应用程序中使用客户端 SSL - 2

    我正在为需要与API建立SSL连接的客户端开发应用程序。我得到了三个文件;一个信任根证书(.cer)文件、一个中间证书(.cer)文件和一个签名的响应文件。我得到的安装说明与IIS或Javakeytool程序有关;我正在用RubyonRails构建应用程序,所以这两种方法都不是一个选项(据我所知)。证书由运行API服务的组织自签名,看来我获得了客户端证书以相互验证https连接。我不确定如何使用我的应用程序中的证书连接和使用API签名响应文件的作用我读过"Usingaself-signedcertificate"和thisarticleonOpenSSLinRuby但两者似乎都不是很到

随机推荐