This forum uses cookies
This forum makes use of cookies to store your login information if you are registered, and your last visit if you are not. Cookies are small text documents stored on your computer; the cookies set by this forum can only be used on this website and pose no security risk. Cookies on this forum also track the specific topics you have read and when you last read them. Please confirm that you accept these cookies being set.

HTTP PUT image to 2N intercom
#8
Thank you so much!
Finally got it working with digest, it could problably be done prettier, but this works for me  Big Grin

Code:
fire = grp.getvalue("32/1/1")

if fire == true then -- Uploads image to intercom
    log("FIREALARM ACTIVE")

    local skthttp = require("socket.http")
    local skturl = require("socket.url")
    local ltn12 = require("ltn12")
    local md5sum = require("encdec").md5

    boundary = os.date("%d%m%Y%H%M%S")
    filedata = io.readfile("/www/scada/resources/img/STOP_DNE_214x320.jpeg") -- image data as a binary string

    body =
        table.concat(
        {
            "--" .. boundary,
            'Content-Disposition: form-data; name="blob-image"; filename="picture.jpeg"',
            "Content-Type: image/jpeg",
            "",
            filedata,
            "--" .. boundary .. "--",
            ""
        },
        "\r\n"
    )

    resp = {}

    local hash = function(...)
        return md5sum(table.concat({...}, ":"))
    end

    local parse_header = function(header)
        local result = {}
        for key, value in (header .. ","):gmatch("(%w+)=(.-),") do
            if value:sub(1, 1) == '"' then -- strip quotes
                result[key:lower()] = value:sub(2, -2)
            else
                result[key:lower()] = value
            end
        end
        return result
    end

    local make_digest_header = function(headers)
        local digest = {}
        for _, header in ipairs(headers) do
            if not header.unquote then
                header[2] = '"' .. header[2] .. '"'
            end

            digest[#digest + 1] = header[1] .. "=" .. header[2]
        end
        return "Digest " .. table.concat(digest, ", ")
    end

    local _request = function(req)
        if not req.url then
            return nil, "missing url"
        end

        local url = skturl.parse(req.url)
        local user, password = url.user, url.password
        local sink = req.sink

        if not user or not password then
            return nil, "missing credentials in url"
        end

        url.user, url.password, url.authority, url.userinfo = nil, nil, nil, nil
        req.url = skturl.build(url)
        local source
        if req.source then
            local chunks = {}
            local capture = function(chunk)
                if chunk then
                    chunks[#chunks + 1] = chunk
                end
                return chunk
            end
            local chunk_id = 0
            source = function()
                chunk_id = chunk_id + 1
                return chunks[chunk_id]
            end
            req.source = ltn12.source.chain(req.source, capture)
        end
        req.sink = nil
        local body, code, hdrs = skthttp.request(req)
        if code == 401 and hdrs["www-authenticate"] then
            local ht = parse_header(hdrs["www-authenticate"])
            if not ht.realm or not ht.nonce then
                return nil, "missing realm/nonce from response"
            end
            local qop = ht.qop
            if qop and qop ~= "auth" then
                return nil, "unsupported qop " .. tostring(qop)
            end
            if ht.algorithm and ht.algorithm:lower() ~= "md5" then
                return nil, "unsupported algo " .. tostring(ht.algorithm)
            end
            local nc = "00000001"
            local cnonce = string.format("%08x", os.time())
            local uri = skturl.build({path = url.path, query = url.query})
            local method = req.method or "GET"
            local response = hash(hash(user, ht.realm, password), ht.nonce, nc, cnonce, "auth", hash(method, uri))
            req.headers = req.headers or {}
            local auth = {
                {"username", user},
                {"realm", ht.realm},
                {"nonce", ht.nonce},
                {"uri", uri},
                {"cnonce", cnonce},
                {"nc", nc, unquote = true},
                {"qop", "auth"},
                {"algorithm", "MD5"},
                {"response", response}
            }
            if ht.opaque then
                table.insert(auth, {"opaque", ht.opaque})
            end
            req.headers.authorization = make_digest_header(auth)
            if not req.headers.cookie and hdrs["set-cookie"] then
                -- not really correct but enough for httpbin
                local cookie = (hdrs["set-cookie"] .. ";"):match("(.-=.-)[;,]")
                if cookie then
                    req.headers.cookie = "$Version: 0; " .. cookie .. ";"
                end
            end
            if req.source then
                req.source = source
            end
            req.sink = sink
            body, code, hdrs = skthttp.request(req)
        end

        return body, code, hdrs
    end

    local request = function(url)
        local t = type(url)
        if t == "table" then
            return _request(table.clone(url))
        elseif t == "string" then
            local req = {}
            local _, code, headers = _request({url = url, sink = ltn12.sink.table(req)})
            return table.concat(req), code, headers
        end
    end

    res, code, response_headers, status =
        request(
        {
            url = "https://test:test@10.0.0.230/api/display/image?display=ext1",
            sink = ltn12.sink.table(resp),
            method = "PUT",
            source = ltn12.source.string(body),
            headers = {
                ["content-length"] = #body,
                ["content-type"] = "multipart/form-data; boundary=" .. boundary
            }
        }
    )

    log(res, code, table.concat(resp))

elseif fire == false then -- Removes image from intercom
    log("Firealarm reset")

    local skthttp = require("socket.http")
    local skturl = require("socket.url")
    local ltn12 = require("ltn12")
    local md5sum = require("encdec").md5

    local hash = function(...)
        return md5sum(table.concat({...}, ":"))
    end

    local parse_header = function(header)
        local result = {}
        for key, value in (header .. ","):gmatch("(%w+)=(.-),") do
            if value:sub(1, 1) == '"' then -- strip quotes
                result[key:lower()] = value:sub(2, -2)
            else
                result[key:lower()] = value
            end
        end
        return result
    end

    local make_digest_header = function(headers)
        local digest = {}
        for _, header in ipairs(headers) do
            if not header.unquote then
                header[2] = '"' .. header[2] .. '"'
            end

            digest[#digest + 1] = header[1] .. "=" .. header[2]
        end
        return "Digest " .. table.concat(digest, ", ")
    end

    local _request = function(req)
        if not req.url then
            return nil, "missing url"
        end

        local url = skturl.parse(req.url)
        local user, password = url.user, url.password
        local sink = req.sink

        if not user or not password then
            return nil, "missing credentials in url"
        end

        url.user, url.password, url.authority, url.userinfo = nil, nil, nil, nil
        req.url = skturl.build(url)
        local source
        if req.source then
            local chunks = {}
            local capture = function(chunk)
                if chunk then
                    chunks[#chunks + 1] = chunk
                end
                return chunk
            end
            local chunk_id = 0
            source = function()
                chunk_id = chunk_id + 1
                return chunks[chunk_id]
            end
            req.source = ltn12.source.chain(req.source, capture)
        end
        req.sink = nil
        local body, code, hdrs = skthttp.request(req)
        if code == 401 and hdrs["www-authenticate"] then
            local ht = parse_header(hdrs["www-authenticate"])
            if not ht.realm or not ht.nonce then
                return nil, "missing realm/nonce from response"
            end
            local qop = ht.qop
            if qop and qop ~= "auth" then
                return nil, "unsupported qop " .. tostring(qop)
            end
            if ht.algorithm and ht.algorithm:lower() ~= "md5" then
                return nil, "unsupported algo " .. tostring(ht.algorithm)
            end
            local nc = "00000001"
            local cnonce = string.format("%08x", os.time())
            local uri = skturl.build({path = url.path, query = url.query})
            local method = req.method or "GET"
            local response = hash(hash(user, ht.realm, password), ht.nonce, nc, cnonce, "auth", hash(method, uri))
            req.headers = req.headers or {}
            local auth = {
                {"username", user},
                {"realm", ht.realm},
                {"nonce", ht.nonce},
                {"uri", uri},
                {"cnonce", cnonce},
                {"nc", nc, unquote = true},
                {"qop", "auth"},
                {"algorithm", "MD5"},
                {"response", response}
            }
            if ht.opaque then
                table.insert(auth, {"opaque", ht.opaque})
            end
            req.headers.authorization = make_digest_header(auth)
            if not req.headers.cookie and hdrs["set-cookie"] then
                -- not really correct but enough for httpbin
                local cookie = (hdrs["set-cookie"] .. ";"):match("(.-=.-)[;,]")
                if cookie then
                    req.headers.cookie = "$Version: 0; " .. cookie .. ";"
                end
            end
            if req.source then
                req.source = source
            end
            req.sink = sink
            body, code, hdrs = skthttp.request(req)
        end

        return body, code, hdrs
    end

    local request = function(url)
        local t = type(url)
        if t == "table" then
            return _request(table.clone(url))
        elseif t == "string" then
            local req = {}
            local _, code, headers = _request({url = url, sink = ltn12.sink.table(req)})
            return table.concat(req), code, headers
        end
    end

    local response_body = {}
    local request_body = ""
    local res, code, response_headers, status =
        request {
        url = "https://test:test@10.0.0.230/api/display/image?display=ext1",
        method = "DELETE",
        source = ltn12.source.string(request_body),
        sink = ltn12.sink.table(response_body),
        protocol = "tlsv1_2"
    }

    if code == 200 then
        log("Image deleted successfully!")
    else
        log("Error deleting image: " .. code)
    end
else
    log("ERROR")
end
Reply


Messages In This Thread
HTTP PUT image to 2N intercom - by coolaew - 07.02.2023, 23:57
RE: HTTP PUT image to 2N intercom - by admin - 08.02.2023, 11:21
RE: HTTP PUT image to 2N intercom - by admin - 09.02.2023, 07:58
RE: HTTP PUT image to 2N intercom - by coolaew - 09.02.2023, 22:13

Forum Jump: